看Thinking in Java中内部类的一章,有内部类和静态内部类,书中把后者叫做嵌套类。常见用法实例:
一般内部类(非静态)
1 public classInnerClassTest {2 public static void main(finalString args[]) {3 SomeOuter outer = newSomeOuter();4 SomeOuter.SomeInner x = outer.newSomeInner();5 x.test();6 }7 }8
9 classSomeOuter {10 public classSomeInner {11 public static final int x = 2;12
13 //public static int y = 2; public static final Integer Z = 2;
14
15 publicSomeInner() {16 System.out.println("inner constructor");17 }18
19 public voidshow() {20 System.out.println("Inner show");21 }22
23 public voidtest() {24 //method in outter class can be invoked directly
25 info();26
27 //inner this & outer this
28 this.show();29 SomeOuter.this.show();30 }31 }32
33 public voidshow() {34 System.out.println("Outer show");35 }36
37 public voidinfo() {38 System.out.println("outer info");39 }40 }41
42 class ExtendedInner extendsSomeOuter.SomeInner {43 public ExtendedInner(final int x, finalSomeOuter outer) {44 outer.super();45 }46
47 }
其中最后的继承内部类用法有点特殊,因为非静态的内部类含有一个外部类的引用(如SomeOuter.this),因而在内部类的派生类中的构造方法也需要提供一个外部类的实例并做如上调用。
非静态内部类中不能含有静态成员(字段和方法),但是final修饰的基本类型除外(也许是因为final修饰的基本类型可以作为编译期常量看待的原因,如果用new Random().nextInt()进行初始化的话也不行,必须用常量值初始化)。
内部类继承
下面的用法估计更加少见,在派生类中对基类的内部类进行继承。由于派生类含有指向基类的引用所以构造内部类时就不用向在外部那样传入一个内部类的外部类实例引用了。
public classInnerClassTest {public static void main(finalString args[]) {
SomeOuterComplex xComplex= newSomeOuterComplex();
xComplex.info();
}
}classSomeOuterBasic {protectedSomeInner inner;publicSomeOuterBasic() {
System.out.println("some out basic constructor");
inner= newSomeInner();
}classSomeInner {publicSomeInner() {
System.out.println("some inner constructor in basic");
}public voidsay() {
System.out.println("some inner basic say");
}
}public voidinfo() {
inner.say();
}
}class SomeOuterComplex extendsSomeOuterBasic {class SomeInner extendsSomeOuterBasic.SomeInner {publicSomeInner() {
System.out.println("some inner constructor in complex");
}
@Overridepublic voidsay() {
System.out.println("some inner complex say");
}
}publicSomeOuterComplex() {
System.out.println("some out complex constructor");
inner= newSomeInner();
}
}
静态内部类与单例模式/延迟初始化
静态内部类没有指向其外部类的引用,因而不能访问其外部类的非静态字段(即实例字段),和一般的类用法最像。当在接口中使用静态内部类时,则可以实现在接口中“放置”一定的代码。
public classInnerClassTest {public static void main(finalString args[]) {
DummyInterface.DoSome.say();
Outer.Inner x= newOuter.Inner();
x.inc();
x.inc();
Singleton.otherThings();
Singleton xSingleton=Singleton.getInstance();
xSingleton.importantThings();
}
}classOuter {publicOuter() {
System.out.println("constructor of Outer");
}public static classInner {private static String name = "Inner Static Class";privateInteger instanceInteger;publicInner() {
instanceInteger= 0;
System.out.println("constructor inner: " +name);
}public voidinc() {
instanceInteger++;
System.out.println(instanceInteger);
}
}
}interfaceDummyInterface {classDoSome {public static voidsay() {
System.out.println("say from DoSome");
}static{
System.out.println("code running in an interface");
}
}
}classSingleton {private static classHolder {static{
System.out.println("static construct in Singleton.Holder");
}public static Singleton instance = newSingleton();
}privateSingleton() {
System.out.println("private singleton constructor");
}public staticSingleton getInstance() {returnHolder.instance;
}public static voidotherThings() {
System.out.println("other things");
}public voidimportantThings() {
System.out.println("instance important things");
}
}
可以用来作为延迟初始化和单例模式,静态内部类在没有使用时静态初始化本分不会进行,但使用到时才会初始化,而且这个机制是JVM保证的,即使在并发情况下依然能够正确运行(因为JVM必须考虑并发时多线程同时对一个类的初次使用的发生)。
匿名内部类
匿名内部类只能实现一个接口,或者继承一个类。因为是匿名的自然就没自己定义的构造函数名称了。
public classInnerClassTest {public static void main(finalString args[]) {
Keyboard enKeyboard= new Keyboard("english keyboard") {
@Overridepublic voidlanguage() {
System.out.println("english");
}
@Overridepublic voidkeys() {
System.out.println("104 keys");
}
};
Keyboard cnKeyboard= new Keyboard("chinese keyboard", "pinyin") {
@Overridepublic voidlanguage() {
System.out.println("chinese");
}
@Overridepublic voidkeys() {
System.out.println("pinyin 101");
}
};
enKeyboard.info();
cnKeyboard.info();
Say enSay= newSay() {
@Overridepublic voidhello() {
System.out.println("hello");
}
@Overridepublic voidbye() {
System.out.println("good bye");
}
};
Say cnSay= newSay() {
@Overridepublic voidhello() {
System.out.println("你好");
}
@Overridepublic voidbye() {
System.out.println("再见");
}
};
enSay.hello();
cnSay.hello();
}
}interfaceSay {voidhello();voidbye();
}abstract classKeyboard {private finalString name;public Keyboard(finalString name) {this.name =name;
}public Keyboard(final String name, finalString extra) {this(name + "-" +extra);
}public voidinfo() {
System.out.println(name);
language();
keys();
}public abstract voidlanguage();public abstract voidkeys();
}
当继承类是调用父类构造函数和一般的继承不一样(不是用super)。
局部内部类
仅在相应的作用域内有效,如果创建了一个实现了接口的实例,则再外部也可以通过接口约定使用,但是除此之外其他成员和方法无法访问了。和一般内部类一样不能在里面定义静态字段和方法,final修饰的基本类型除外。
1 public classInnerClassTest {2 public static void main(finalString args[]) {3 Say impl =buildSayObj();4
5 impl.hello();6
7 }8
9 private staticSay buildSayObj() {10 class Temp implementsSay {11 //public static final Integer x = 1;
12 @Override13 public voidhello() {14 System.out.println("glad to see you!");15 }16
17 //public static void other() {18 //}
19 }20 return newTemp();21 }22 }23
24 interfaceSay {25 voidhello();26 }