class Outer {
public class Inner {
public String getInnerClassName() {
return Inner.this.getClass().toString(); // 'Inner' can be omitted here
}
public String getOuterClassName() {
return Outer.this.getClass().toString(); // 'Outer' CANNOT be omitted here
}
}
public Inner createInner() {
return new Inner();
// return this.new Inner(); // also OK here
}
}
public class InnerTest {
public static void main(String[] args) {
Outer o = new Outer();
Outer.Inner i1 = o.new Inner();
Outer.Inner i2 = o.createInner();
System.out.println(i1.getOuterClassName());
System.out.println(i2.getInnerClassName());
}
}
//output:
/*
class Outer
class Outer$Inner
*/
.new
内部类对象是不能直接创建的。必须先创建一个外部类对象,再由这个外部类对象来创建内部类对象。这样处理可能是为了体现内部类对象是依存外部类对象存在的,即内部类对象不能脱离外部类对象而存在。一个外部类对象可以创建多个内部类对象 (类似 Process 与 Thread 的关系)。创建方法有2种:
- OuterClassObj.new InnerClass():即使用 .new 和内部类构造器,如上面代码中的:
Outer.Inner i1 = o.new Inner();
- OuterClassObj.InnerClassConstructorProxy():即使用在外部类中定义的内部类构造器的代理方法,如上面代码中的:
Outer.Inner i2 = o.createInner();
上面2种方法其实是等价的。
这里注意,内部类的声明类型必须是 Outer.Inner,编译出的文件为 Outer$Inner.class。
.this
其实可以把 this 当作 class 的一个 static field,就算不用内部类,也可以照样用 class.this 形式,如上面代码中的:
public String getInnerClassName() {
return Inner.this.getClass().toString(); // 'Inner' can be omitted here
}
不过鉴于内部类和外部类的特殊关系,内部类必须能够访问其创建者,所以在内部类中可以使用 Outer.this 来指向创建这个内部类对象的外部类对象。如:
public String getOuterClassName() {
return Outer.this.getClass().toString(); //'Outer' CANNOT be omitted here
}
总结一点,.this 与 class 连用 (class.this),.new 与 reference 连用 (obj.new)。
对外部类的field和method的访问
就如同我们在一般类的方法或是 constructor 中省略 this 一样,内部类的方法也是如此,只是内部类中省略的是 this (i.e. Inner.this) 和 Outer.this 这2个 this。所以 看上去 在内部类的方法中可以直接访问外部类的 field/method,而且无论是哪种访问权限的 field/method 都可以访问,其实是因为内部类方法中可以通过 Outer.this 链接到外部类,由外部类来访问外部类的 field/method,自然是可以不考虑访问权限了。
如果内部类和外部类有 同名 的 field/method,单纯使用 SameFieldName 或是 SameMethodName() 会被优先识别为内部类的 field/method,如果想要用外部类的 field/method,必须用 Outer.this 来指定。
如果你手中只有内部类对象,比如 i1、i2,这样是无法直接访问外部类的 field/method 的,因为外部类的 field/method 并不属于内部类,类似 i1.OuterField 或是 i2.OuterMethod() 是无法通过编译的。所以 i1、i2 想要访问外部类的 field/method 只能间接通过内部类的方法。
总之,简单的说,内部类对象要想访问外部类对象的 field 或是 method 的话,必须要先获得创建自己的外部类对象的引用。