什么是内部类
内部类(inner class),是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。
内部类可为静态,可用protected和private修饰(而外部类只能使用public和缺省的包访问权限)。
内部类主要有以下几类:成员内部类、局部内部类、静态内部类、匿名内部类
为什么要使用内部类
主要原因有以下三点:
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据
- 内部类可以对同一个包中的其他类隐藏起来
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷
此外,每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。
成员内部类
作为外部类的一个成员存在,与外部类的属性、方法并列。
public class OutterClass {private String name;private int age;public void getInnerClass(){InnerClass innerClass = new InnerClass();System.out.println(innerClass);}//一个内部类class InnerClass{private String nickName;private String name;void hello(){System.out.println("Hello" + OutterClass.this.name);}}}
对于成员内部类来说,有以下需要注意的规则:
- 成员内部类中,不能定义静态成员
- 成员内部类中,可以访问外部类的所有成员
class InnerClass{private String nickName;private String name;void hello(){//在内部类中,访问自己的变量时直接使用变量名,也可以使用this.变量名System.out.println(nickName);System.out.println(this.nickName);//在内部类中访问外部类中与内部类同名的实例变量用外部类名.this.变量名System.out.println(OutterClass.this.name);//如果内部类中没有与外部类同名的变量,则可以直接用变量名访问外部类变量System.out.println(name);}}
- 创建内部类的对象时,必须由此外围类的一个对象来创建其内部类的一个对象
public class OutterClass {private String name;private int age;//外部类的非静态方法访问成员内部类public void getInnerClass(){InnerClass innerClass = new InnerClass();System.out.println(innerClass);}//外部类的静态方法访问成员内部类,和外部类的外部访问内部类的方法一样public static void get(){OutterClass outterClass = new OutterClass();InnerClass innerClass = outterClass.new InnerClass();}//一个内部类class InnerClass{private String nickName;private String name;}}
由此可见,在该外部类的外部,已经该外部类的静态方法里,想要访问到内部类,都要通过该外部类的对象去创建其内部类的对象,语法如下:
OutterClass outterClass = new OutterClass(); InnerClass innerClass = outterClass.new InnerClass();
原因是在内部类的对象被创建的时候,内部类的对象会悄悄地链接到创建它地外部类地对象,从而获得它地一个隐式引用。因此,除非你已经有了外部类的一个对象,否则不可能生成内部类的对象。当然,如果是静态内部类则不需要对其外部类对象的引用。
- 只有内部类可以是私有类,而常规类只可以是protected或public
- 内部类中声明地所有静态域都必须是final
- 内部类不允许有static方法
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。 对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。
局部内部类
在方法中定义的内部类称为局部内部类。与局部变量类似,局部内部类不能有访问说明符,因为它不是外部类的一部分,但是它可以访问当前代码块内的常量,和此外部类所有的成员。
public class OutterClass {private String name;private int age;//方法里定义了一个局部内部类public void getInnerClass(){int i = 10;class InnerClass{int j = 100;void get(){i++; //Error 不可以修改外部变量的值System.out.println(i);}}InnerClass innerClass = new InnerClass();System.out.println(innerClass);}}
局部类不能public或private访问说明符进行声明,它的作用域被限定在声明这个局部类的块(方法)中。
局部类有一个优势,即是对外部世界可以完全地隐藏起来。即是是OutterClass类中的其他代码也不能访问它。
此外,与其他内部类相比较,局部类还有一个优点。它们不仅能够访问包含它们的外部类,还可以访问局部变量。但是,那些局部变量必须事实上为final。
匿名内部类
匿名内部类(anonymous inner class),简单地说:匿名内部类就是没有名字的内部类。什么情况下需要使用匿名内部类?如果满足下面的一些条件,使用匿名内部类是比较合适的:
- 只用到类的一个实例。
- 类在定义后马上用到。
- 类非常小(SUN推荐是在4行代码以下)
- 给类命名并不会导致你的代码更容易被理解。
在使用匿名内部类时,要记住以下几个原则:
- 匿名内部类不能有构造方法。
- 匿名内部类不能定义任何静态成员、方法和类。
- 匿名内部类不能是public,protected,private,static。
- 只能创建匿名内部类的一个实例。
- 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
- 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。
public void start(){//这就是一个匿名类,ActionListener是一个函数式接口,创建了一个匿名内部类实现了该接口ActionListener actionListener = new ActionListener(){public void actionPerformed(ActionEvent event){//}}}
因为匿名内部类不能有构造器,但是我们需要一个有参构造器的时候应该怎么办?
这时我们只需简单地传递合适的参数给基类的构造器即可,这里是将x 传进new Wrapping(x)。
public class Parcel7 {public static void main(String[] args) {Parcel7 p = new Parcel7();Wrapping w = p.wrap(10);}public Wrapping wrap(int x) {// Base constructor call:// Pass constructor argument.return new Wrapping(x) {public int value() {return super.value() * 47;}}; // Semicolon required}}
如果你有一个匿名内部类,它要使用一个在它的外部定义的对象,编译器会要求其参数引用是final 型的。
静态内部类
如果你不需要内部类对象与其外围类对象之间有联系,那你可以将内部类声明为static。这通常称为嵌套类(nested class)。想要理解static应用于内部类时的含义,你就必须记住,普通的内部类对象隐含地保存了一个引用,指向创建它的外围类对象。然而,当内部类是static的时,就不是这样了。嵌套类意味着:
- 要创建嵌套类的对象,并不需要其外围类的对象。
- 不能从嵌套类的对象中访问非静态的外围类对象。
单例模式:由于静态内部类的加载机制,决定了他可以使用来处理单例模式,而且性能客观
public class Outer {private static int i = 1;private int j = 10;public static void outerF1() {}public void outerF3() {// 外部类访问内部类的静态成员:内部类.静态成员System.out.println(Inner.inner_i);Inner.innerF1();// 外部类访问内部类的非静态成员:实例化内部类即可Inner inner = new Inner();inner.innerF2();}/*** 静态内部类可以用public,protected,private修饰* 静态内部类中可以定义静态或者非静态的成员*/static class Inner {static int inner_i = 100;int innerJ = 200;static void innerF1() {// 静态内部类只能访问外部类的静态成员(包括静态变量和静态方法)System.out.println("Outer.i" + i);outerF1();}void innerF2() {// 静态内部类不能访问外部类的非静态成员(包括非静态变量和非静态方法)// System.out.println("Outer.i"+j);// outerF2();}}}
正常情况下,你不能在接口内部放置任何代码,但嵌套类可以作为接口的一部分,因为它是static 的。只是将嵌套类置于接口的命名空间内,这并不违反接口的规则。另外,声明在接口中的内部类自动成为static和public类
与常规内部类不同,静态内部类可以有静态域和方法。此外,静态内部类只能访问外部类的静态成员。

