Java 中的内部类
参考资料:
《Java SE 6.0 编程指南》 作者:吴亚峰 纪超 出版社:人民邮电出版社
《Thinking in Java Fourth Edition》 作者:Bruce Eckel
public class Outer { /** * 非静态内部类 */ class Inner { //内部类的成员 int i = 1; } //外部类的普通成员 int count = 2; }
package innerclasses; // Creating inner classes. public class Parcel1 { class Contents { private int i = 11; public int value() { return i; } } class Destination { private String label; Destination(String whereTo) { label = whereTo; } String readLabel() { return label; } } // Using inner classes looks just like // using any other class, within Parcel1: public void ship(String dest) { Contents c = new Contents(); Destination d = new Destination(dest); System.out.println(d.readLabel()); } public static void main(String[] args) { Parcel1 p = new Parcel1(); p.ship("Tasmania"); } } /* Output: Tasmania *///:~
□ 内部类和外部类中的其他成员是一个级别的,其也是外部类的一个成员。
□ 在内部类也是一个单独的类,也有自己的成员变量和方法。
□ 内部类可以加上访问限制修饰符,包括 private、protected 和 public。
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 内部类 */ class Inner { /** * 打印输出 */ public void show() { System.out.println("调用内部类的show方法"); } } /** * 外部类的方法,创建内部类对象 */ public void createInner() { //外部类中创建内部类对象 Inner inner = new Inner(); //调用内部类的方法 inner.show(); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建外部类对象 Outer outer = new Outer(); //调用创建内部类对象的方法 outer.createInner(); } }
□ 外部类中创建内部类对象的语法与普通创建对象的方法相同,使用 new 操作符调用构造器。
□ 对内部类而言,在其类体中也可以拥有类所能拥有的一切成员。
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 内部类 */ class Inner { /** * 打印输出 */ public void show() { System.out.println("调用内部类的show方法"); } } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建外部类对象 Outer outer = new Outer(); //创建内部类对象 Outer.Inner inner = outer.new Inner(); Outer.Inner inner2 = new Outer().new Inner(); //调用内部类中的方法 inner.show(); inner2.show(); } }
□ 在外部类之外声明内部类引用时,需用外部类名加以标识,不能直接使用内部类类名,而创建内部类对象时,需先创建外部类对象,再创建内部类对象。
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** 外部类的私有成员变量 */ private int o = 1; /** * 内部类 */ class Inner { /** * 打印输出外部类的私有成员 */ public void show() { System.out.println("外部类的私有成员变量o = " + o); } } public int getO() { return o; } public void setO(int o) { this.o = o; } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建内部类对象 Outer.Inner inner = new Outer().new Inner(); //调用内部类中的方法 inner.show(); } }
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 内部类 */ class Inner { /** * 打印输出 */ private void show() { System.out.println("成功访问内部类的私有方法"); } } /** * 创建内部类对象并调用其方法 */ public void getInner() { //创建内部类对象 Inner inner = new Inner(); //访问内部类私有方法 inner.show(); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建外部类对象,并调用创建内部类方法 Outer outer = new Outer(); outer.getInner(); } }
□ 内部类中需要使用外部类对象的 this,语法如下:<外部类名>.this.<外部类中需要被访问的成员名>。
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** 外部类成员变量 */ int i = 1; /** * 内部类 */ class Inner { /** 内部类与外部类同名成员变量 */ int i = 10; /** * 输出外部类和内部类的成员变量 */ public void show() { //访问外部类的成员变量 System.out.println("外部类的成员变量 i = " + Outer.this.i); //访问内部类的成员变量 System.out.println("内部类的成员变量 i = " + this.i); } } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建内部类对象 Outer.Inner innerr = new Outer().new Inner(); //调用内部类方法 innerr.show(); } }
package innerclasses; // Qualifying access to the outer-class object. public class DotThis { void f() { System.out.println("DotThis.f()"); } public class Inner { public DotThis outer() { return DotThis.this; // A plain "this" would be Inner's "this" } } public Inner inner() { return new Inner(); } public static void main(String[] args) { DotThis dt = new DotThis(); DotThis.Inner dti = dt.inner(); dti.outer().f(); } } /* Output: DotThis.f() *///:~
package innerclasses; // Inheriting an inner class. class WithInner { class Inner {} } public class InheritInner extends WithInner.Inner { public InheritInner(WithInner inner) { inner.super(); //若跳过外部类直接继承内部类,必须使用此语法才能编译通过 } public static void main(String[] args) { WithInner wi = new WithInner(); InheritInner ii = new InheritInner(wi); } }
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 声明并创建内部类对象 */ public void getInner() { /** * 内部类 */ class Inner { /** * 输出 */ public void show() { System.out.println("内部类的show()方法"); } } //创建内部类对象并调用其方法 Inner inner = new Inner(); inner.show(); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建外部类对象 Outer outer = new Outer(); //调用外部类方法 outer.getInner(); } }
package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 声明并创建内部类对象 */ public void getInner() { /** 定义局部变量 */ final int i = 2; /** * 内部类 */ class Inner { /** * 输出 */ public void show() { System.out.println("方法中的局部变量 i = " + i); } } //创建内部类对象并调用其方法 Inner inner = new Inner(); inner.show(); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建外部类对象 Outer outer = new Outer(); //调用外部类方法 outer.getInner(); } }
□ 局部变量与局部内部类。普通局部变量随着语句块的结束而消亡,而创建的局部类对象则不会。如果在语句块结束后,调用了局部内部类对象中访问普通局部变量的方法,就会出现问题,因为要访问的局部变量已经不存在了。
□ final 的局部变量不会因为语句块的结束而消失,因此可以被局部内部类访问。
/** * */ package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** 外部类的静态成员变量 */ static int i = 7; /** * 声明并创建内部类对象 */ public static void getInner() { /** * 内部类 */ class Inner { /** * 输出 */ public void show() { System.out.println("方法中的局部变量 i = " + i); } } //创建内部类对象并调用其方法 Inner inner = new Inner(); inner.show(); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //调用外部类静态方法 Outer.getInner(); } }
□ 若局部类位于静态方法中,则只能访问外部类的静态成员,这与静态方法访问成员的规则是一致的。
/** * */ package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 静态内部类 */ static class Inner { /** * 输出 */ public void show() { System.out.println("静态内部类的show()方法"); } } /** * 声明并创建内部类对象 */ public void getInner() { //创建内部类对象并调用其方法 Inner inner = new Inner(); inner.show(); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //外部类之外创建静态内部类对象 Outer.Inner inner = new Outer.Inner(); inner.show(); //外部类中使用静态内部类对象 new Outer().getInner(); } }
□ 外部类之外创建静态内部类对象的语法如下:<外部类类名>.<内部类类名> 引用变量 = new <外部类类名>.<内部类构造器>;
□ 静态内部类也可以称为静态嵌套类,或顶级嵌套类。由于创建静态内部类的对象已不需要外部类对象的存在,静态内部类其实只是一个在别的类中的一个普通类而已。static 关键字只是说明其创建对象时不依赖于外部类对象,并不表示这个类是静态的。
□ 匿名内部类没有类名,因此匿名内部类在声明的同时也创建了对象。
□ 匿名内部类的声明要么是基于继承的,要么是基于接口实现的。
/** * */ package com.aimartt.innerclass; /** * 父类 */ class Father { public void show() { System.out.println("父类中的show()方法"); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //定义匿名内部类并创建其对象,并重写父类中的方法 Father father = new Father() { public void show() { System.out.println("重写父类的show()方法"); } }; //访问匿名内部类中重写的方法 father.show(); } }
□ 访问匿名内部类成员均是通过多态完成的,因为匿名内部类无法创建自身类型的引用。
/** * */ package com.aimartt.innerclass; /** * 定义接口 */ interface MyInterface { void show(); } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //定义匿名内部类并创建其对象,并实现接口中的方法 MyInterface mi = new MyInterface() { @Override public void show() { System.out.println("实现接口的show()方法"); } }; //访问匿名内部类中实现的方法 mi.show(); } }
□ 匿名内部类要么实现一个接口,要么继承一个类,不能同时既实现接口又进行继承。
/** * */ package com.aimartt.innerclass; /** * 定义抽象类 */ abstract class Father { int i; abstract void show(); } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //定义匿名内部类并创建其对象 Father mi = new Father() { //使用非静态块初始化成员 { i = (int) (Math.random() * 100); } //重写抽象类中的方法 @Override public void show() { System.out.println("初始化的成员i = " + i); } }; //访问匿名内部类中实现的方法 mi.show(); } }
□ 匿名内部类对象的初始化代码写在非静态语句块中。
package innerclasses; // An anonymous inner class that performs initialization. interface Destination { String readLabel(); } public class Parcel9 { // Argument must be final to use inside anonymous inner class: public Destination destination(final String dest) { return new Destination() { private String label = dest; @Override public String readLabel() { return label; } }; } public static void main(String[] args) { Parcel9 p = new Parcel9(); Destination d = p.destination("Tasmania"); } }□ 从外部传递给匿名内部类的参数,必须是 final 的。
/** * */ package com.aimartt.innerclass; /** * 外部类 */ class Outer { /** * 非静态内部接口 */ public interface InnerInterface { void show(); } /** * 实现内部接口的内部类 */ public class Inner implements InnerInterface { @Override public void show() { System.out.println("内部类实现内部接口的show()方法"); } } /** * 获取内部类对象的方法 * @return */ public InnerInterface getInner() { return new Inner(); } } /** * 实现内部接口的普通类 */ class Normal implements Outer.InnerInterface { @Override public void show() { System.out.println("普通类实现了内部接口的show()方法"); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { Outer outer = new Outer(); //创建外部类对象 Outer.InnerInterface oic = outer.getInner(); //获取内部类对象 oic.show(); //访问内部类的show()方法 oic = new Normal(); //获取普通类的对象 oic.show(); //访问普通类的show()方法 } }
□ 内部接口无论是否使用 static 修饰,扮演的都是静态成员。
/** * */ package com.aimartt.innerclass; /** * 外部接口 */ interface OuterInterface { /** * 内部接口 */ public interface InnerInterface { void inShow(); } /** * 外部接口的方法 */ void outShow(); } /** * 实现外部接口的类 */ class OuterInterfaceImpl implements OuterInterface { @Override public void outShow() { System.out.println("实现外部接口的outShow()方法"); } } /** * 实现内部接口的类 */ class InnerInterfaceImpl implements OuterInterface.InnerInterface { @Override public void inShow() { System.out.println("实现内部接口的inShow()方法"); } } /** * 主类 */ public class Demo { /** * 主方法 * @param args */ public static void main(String[] args) { //创建实现内部接口和外部接口的类的对象 OuterInterface.InnerInterface inner = new InnerInterfaceImpl(); OuterInterface outer = new OuterInterfaceImpl(); //调用两个对象的方法 inner.inShow(); outer.outShow(); } }
□ 内部接口只是把普通接口放到了一个接口内部,在使用上没有很大的不一样,实现内部接口与普通接口的具体方法完全一样。