# 内部类

loading

内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性,然而必须要了解,内部类与组合是完全不同的概念,这一点很重要。

# 一、创建内部类

如果想从外部类的非静态方法之外的任意位置创建某个内部类对象,例如这里的 main() 方法,必须具体地指明这个对象的类型。

public class Outer {

    class Inner {

    }

    Inner inner() {
        return new Inner();
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        // 如果想从外部类的非静态方法之外的任意位置创建某个内部类对象,例如这里的 main() 方法,必须具体地指明这个对象的类型。
        Outer.Inner inner = outer.inner();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 二、链接到外部类

当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权。

interface Selector {
    boolean end();

    Object current();

    void next();
}

public class Sequence {

    private Object[] items;
    private int next = 0;

    public Sequence(int size) {
        items = new Object[size];
    }

    public void add(Object x) {
        if (next < items.length)
            items[next++] = x;
    }

    private class SequenceSelector implements Selector {
        private int i = 0;

        public boolean end() {
            return i == items.length;
        }

        public Object current() {
            return items[i];
        }

        public void next() {
            if (i < items.length) i++;
        }
    }

    public Selector selector() {
        return new SequenceSelector();
    }

    public static void main(String[] args) {
        Sequence sequence = new Sequence(10);
        for (int i = 0; i < 10; i++) {
            sequence.add(Integer.toString(i));
        }
        Selector selector = sequence.selector();
        while (!selector.end()) {
            System.out.print(selector.current() + " ");
            selector.next();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

执行结果:

0 1 2 3 4 5 6 7 8 9 
1

# 三、使用.this与.new

如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟 .this。这样产生引用自动地具有正确的类型。这一点在编译器就被知晓并受到检查,因此没有任何运行时开销。

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();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

执行结果:

DotThis.f()
1

有时你可能想要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在 new 表达式中提供对其他外部类对象的引用,这时需要使用 .new 语法。

public class DotNew {
    public class Inner {
    }

    public static void main(String[] args) {
        DotNew dn = new DotNew();
        DotNew.Inner dni = dn.new Inner();
    }
}
1
2
3
4
5
6
7
8
9

在拥有外部类对象之前是不可能创建内部类对象的。这时因为内部类对象会暗暗地连接到创建它的外部类对象上。但是,如果你创建的是嵌套类(静态内部类),那么它就不需要对外部类对象的引用。

public class Parcel3 {

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

    public static void main(String[] args) {
        Parcel3 p = new Parcel3();
        // Must use instance of outer class
        // to create an instance of the inner class:
        Parcel3.Contents c = p.new Contents();
        Parcel3.Destination d = p.new Destination("Tasmania");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 四、内部类与向上转型

当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。这是因为此内部类——某个接口的实现——能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便的隐藏实现细节。

内部类就相当于一个外部类的成员变量,所以可以直接访问外部变量,外部类不能直接访问内部类变量,必须通过创建内部类实例的方法访问。

public class Outer {

    class Inner {
        private int value = 1;

        private void show() {
            System.out.println(value);
        }
    }

    void testValue() {
        System.out.println(new Inner().value);
    }

    void testShow() {
        new Inner().show();
    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.testValue();
        outer.testShow();
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

执行结果:

1
1
1
2

上次更新: 2020-08-21 09:02:51(10 小时前)