Java 成员内部类,与静态内部类相比,成员内部类没有static修饰符,少了一个static修饰符,含义有很大不同,下面我们详细讨论。我们看个成员内部类的例子,代码如下所示。
public class Outer {
private int a = 100;
public class Inner {
public void innerMethod(){
System.out.println("outer a " +a);
Outer.this.action();
}
}
private void action(){
System.out.println("action");
}
public void test(){
Inner inner = new Inner();
inner.innerMethod();
}
}
Inner就是成员内部类,与静态内部类不同,除了静态变量和方法,成员内部类还可以直接访问外部类的实例变量和方法,如innerMethod直接访问外部类私有实例变量a。成员内部类还可以通过“外部类.this.xxx”的方式引用外部类的实例变量和方法,如Outer.this. action()
,这种写法一般在重名的情况下使用,如果没有重名,那么“外部类.this.”是多余的。
在外部类内,使用成员内部类与静态内部类是一样的,直接使用即可,如test()方法所示。与静态内部类不同,成员内部类对象总是与一个外部类对象相连的,在外部使用时,它不能直接通过new Outer.Inner()
的方式创建对象,而是要先将创建一个Outer类对象,代码如下所示:
public class coolcou {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.innerMethod();
}
}
运行结果如下:
创建内部类对象的语法是“外部类对象.new 内部类()”,如outer.new Inner()
。
与静态内部类不同,成员内部类中不可以定义静态变量和方法(final变量例外,它等同于常量),下面介绍的方法内部类和匿名内部类也都不可以。Java为什么要有这个规定呢?可以这么理解,这些内部类是与外部实例相连的,不应独立使用,而静态变量和方法作为类型的属性和方法,一般是独立使用的,在内部类中意义不大,而如果内部类确实需要静态变量和方法,那么也可以挪到外部类中。
成员内部类背后是怎么实现的呢?上述代码会生成两个类:一个是Outer,另一个是Outer$Inner
,它们的代码大概如下所示。
public class Outer {
private int a = 100;
private void action() {
System.out.println("action");
}
public void test() {
Outer$Inner inner = new Outer$Inner(this);
inner.innerMethod();
}
static int access$0(Outer outer) {
return outer.a;
}
static void access$1(Outer outer) {
outer.action();
}
}
public class Outer$Inner {
final Outer outer;
public Outer$Inner(Outer outer){
ths.outer = outer;
}
public void innerMethod() {
System.out.println("outer a " + Outer.access$0(outer));
Outer.access$1(outer);
}
}
Outer$Inner
类有个实例变量outer指向外部类的对象,它在构造方法中被初始化,Outer在新建Outer$Inner对象时给它传递当前对象,由于内部类访问了外部类的私有变量和方法,外部类Outer生成了两个非私有静态方法:access$0
用于访问变量a, access$1
用于访问方法action。
成员内部类有哪些应用场景呢?如果内部类与外部类关系密切,需要访问外部类的实例变量或方法,则可以考虑定义为成员内部类。外部类的一些方法的返回值可能是某个接口,为了返回这个接口,外部类方法可能使用内部类实现这个接口,这个内部类可以被设为private,对外完全隐藏。
比如,在Java API的类LinkedList中,它的两个方法listIterator和descendingIterator的返回值都是接口Iterator,调用者可以通过Iterator接口对链表遍历,listIterator和descend-ingIterator内部分别使用了成员内部类ListItr和DescendingIterator,这两个内部类都实现了接口Iterator。
评论前必须登录!
注册