内部类的好处:提供更好地封装和方便访问外部类的私有成员。
1. 非静态内部类
public class Temp { public static void main (String args[]) { Outer outer = new Outer(); outer.print(); } } class Outer{ private String name = "Outer class"; public String getName() { return this.name; } public void print() { new Inner().printInfo(); } private class Inner{ private String name = "Inner class"; public void printInfo(){ System.out.println(this.name); //访问本类成员 System.out.println(Outer.this.name); //访问外部类成员 System.out.println(Outer.this.getName()); //访问外部类方法 } } }
1.1 编译Outer类会生成两个class文件:Outer.class和Outer$Inner.class。
1.2 非静态内部类中可以任意访问外部类的非静态成员和方法。
1.3 在非静态内部类中访问一个变量时,系统会优先在方法内部查找该变量,其次在内部类中,再在外部类中。如果内部类和外部类中存在相同名字的成员,则使用this.name代表内部类成员,使用Outer.this.name代表外部类成员。
1.4 外部类必须先显示创建内部类实例才能调用内部类的成员和方法。因为创建外部类实例并不代表着内部类实例也创建了。但是如果一个内部类实例创建了,那包裹它的外部类实例一定已经被创建了。
1.5 在非静态内部类中不能定义静态的成员,代码块和方法。如果非要定义,只能使用static final的。
1.6 根据静态成员不能访问非静态成员的规则,外部类中的静态成员不能访问非静态内部类的成员。除了非静态内部类中的static final成员。
1.7 在外部类以外的地方创建内部类实例的格式:外部类实例.new 内部类实例。前提是内部类的访问权限可以让外部类之外的环境访问。例如:
public class Temp { public static void main (String args[]) { Outer.Inner inner = new Outer().new Inner(); inner.printInfo(); } } class Outer{ private String name = "Outer class"; public String getName() { return this.name; } public void print() { new Inner().printInfo(); } public class Inner{ private String name = "Inner class"; public void printInfo(){ System.out.println(this.name); //访问本类成员 System.out.println(Outer.this.name); //访问外部类成员 System.out.println(Outer.this.getName()); //访问外部类方法 } } }
1.8 子类继承非静态内部类:注意子类的构造方法中一定要有被继承的内部类的外部类的实例。
public class Temp { public static void main (String args[]) { SubInner subInner = new SubInner(new Outer("外部类")); System.out.println(subInner.name); //输出"子类",因为SubInner构造方法中调用的是Inner类的构造器,将"子类"字符串赋值到了Inner类中的name变量。 } } class Outer{ //外部类 public String name; public Outer(String name) { //外部类构造方法 this.name = name; System.out.println(this.name); //输出"外部类",main方法中调用Outer类构造器的时候传入。 } public class Inner{ //非静态内部类 public String name; public Inner (String name) { //非静态内部类构造方法 this.name = name; } } } class SubInner extends Outer.Inner { public SubInner(Outer outer) { outer.super("子类"); //通过传入out的对象显示调用Inner类的构造器。注意:这里调的是Inner的构造器,不是Outer的。 } }
2. 静态内部类
public class Temp { public static void main (String args[]) { Outer outer = new Outer(); outer.print(); } } class Outer{ private static String name = "Outer class"; public static String getName() { return name; } public void print() { System.out.println(Inner.name); new Inner().printInfo(); } private static class Inner{ private static String name = "Inner class"; public void printInfo(){ System.out.println(Inner.name); //访问本类成员 System.out.println(Outer.name); //访问外部类成员 System.out.println(Outer.getName()); //访问外部类方法 } } }2.1 只有静态内部类中才可以包含静态成员。静态内部类中的静态成员不能访问外部类的非静态成员。
2.2 在外部类以外的地方创建静态内部类实例的格式:new 外部类类名.内部类实例。因为静态内部类是其外部类类相关的,因此创建静态内部类实例的时候不需要外部类的实例。
public class Temp { public static void main (String args[]) { Outer.Inner inner = new Outer.Inner(); inner.print(); } } class Outer{ private String name = "Outer class"; public String getName() { return this.name; } public static class Inner{ private String name = "Inner class"; public void print() { System.out.println("内部类方法"); } } }
2.3 子类继承静态内部类:不需要外部类的实例。
public class Temp { public static void main (String args[]) { SubInner subInner = new SubInner(); System.out.println(subInner.name); //输出"子类"。 } } class Outer{ //外部类 public String name; public Outer(String name) { //外部类构造方法 this.name = name; System.out.println(this.name); //不会执行,因为实例化静态内部类的时候不需要调用外部类的构造器。 } public static class Inner{ //静态内部类 public String name; public Inner (String name) { //静态内部类构造方法 this.name = name; } } } class SubInner extends Outer.Inner { public SubInner() { super("子类"); //不需要传入out的对象。很显然,这里调的是Inner的构造器。 } }
3. 局部内部类:将内部类放在方法定义里。
public class Temp { public static void main (String args[]) { class Inner { //局部内部类 int a = 1; } class SubInner extends Inner { //第二个局部内部类,继承第一个局部内部类 int b = 2; } Inner inner = new Inner(); //创建局部内部类实例 System.out.println(inner.a); SubInner subInner = new SubInner(); System.out.println(subInner.a + " " + subInner.b); } }3.1 因为局部内部类定义在方法内,因此局部内部类的适用范围仅在该方法里。根据所有局部成员都不存在访问控制符和static的原则:局部内部类不可能被外部类以外的地方使用,因此也无需使用访问控制符和static。
3.2 编译上面程序后会生成三个class文件:Temp.class,Temp$1Inner.class,Temp$1SubInner.class。注意到局部内部类的class文件名比内部类多了一个"1"。这是因为在一个类中不可能有重名的内部类,但是有可能有重名的局部内部类(在不同方法中定义)。这个数字便用于区分同名的局部内部类。
4. 匿名内部类:只是用一次的类。
4.1 匿名内部类创建后会立即生成该类实例,然后类定义消失。因此该类只能使用一次。定义匿名内部类的格式是:new 父类构造器 (参数列表|实现接口)。
4.2 匿名内部类必须且只能继承一个父类或实现一个接口。
4.3 匿名内部类不可能是抽象类,因为要生成类实例。
4.4 匿名内部类不能定义构造方法,但是可以有构造块。一般都是通过构造块完成构造方法的事情。
4.5 创建实现接口的匿名内部类的例子:
public class Temp { public void testWork(Workable workable) { //该方法需要传入一个实现Workable接口的实例 System.out.println(workable.work()); } public static void main (String args[]) { new Temp().testWork(new Workable() { //定义匿名内部类,实现Workable接口 public String work() { return ("工作"); } }); } } interface Workable { //定义一个接口,匿名内部类实现的便是这个接口 public String work(); }4.6 创建继承父类的匿名内部类的例子:
public class Temp { public void testWork(Father father) { //该方法需要传入一个继承Father类的实例 System.out.println(father.work()); } public static void main (String args[]) { new Temp().testWork(new Father("继承父类的匿名内部类") { //继承父类的匿名内部类 public String work() { //重写父类的work方法 return this.name + "在新地方工作"; } }); } } class Father { //定义一个父类 public String name; public Father(String name) { //定义父类的构造方法,需要传入一个String参数 this.name = name; } public String work() { return this.name + "在工作"; } }
4.7 匿名内部类访问类外部的局部变量,该局部变量必须是final的,否则不能访问。
public class Temp { public void testWork(Father father) { //该方法需要传入一个继承Father类的实例 System.out.println(father.work()); } public static void main (String args[]) { final String newName = "类外部的局部变量"; //必须定义成final的 new Temp().testWork(new Father() { //继承父类的匿名内部类 public String work() { //重写父类的work方法 return newName + "在工作"; //newName必须是final的,否则编译报错 } }); } } class Father { //定义一个父类 public String name = "父类"; public String work() { return this.name + "在工作"; } }