Java 成员内部类

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();
    }
}

运行结果如下:
Java 成员内部类

创建内部类对象的语法是“外部类对象.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。

赞(0)

评论 抢沙发

评论前必须登录!