企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## [链接外部类](https://lingcoder.gitee.io/onjava8/#/book/11-Inner-Classes?id=%e9%93%be%e6%8e%a5%e5%a4%96%e9%83%a8%e7%b1%bb) 到目前为止,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,但还不是最引人注目的,它还有其他的用途。当生成一个内部类的对象时,此对象与制造它的外部对象(enclosing object)之间就有了一种联系,所以它能访问其外部对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外部类的所有元素的访问权。 ~~~ // innerclasses/Sequence.java // Holds a sequence of Objects 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; @Override public boolean end() { return i == items.length; } @Override public Object current() { return items[i]; } @Override 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(); } } } ~~~ 输出为: ~~~ 0 1 2 3 4 5 6 7 8 9 ~~~ **Sequence**类只是一个固定大小的**Object**的数组,以类的形式包装了起来。可以调用`add()`在序列末尾增加新的**Object**(只要还有空间),要获取**Sequence**中的每一个对象,可以使用**Selector**接口。这是“迭代器”设计模式的一个例子,在本书稍后的部分将更多地学习它。**Selector**允许你检查序列是否到末尾了(`end()`),访问当前对象(`current()`),以及移到序列中的下一个对象(`next()`)。因为**Selector**是一个接口,所以别的类可以按它们自己的方式来实现这个接口,并且其他方法能以此接口为参数,来生成更加通用的代码。 这里,**SequenceSelector**是提供**Selector**功能的**private**类。可以看到,在`main()`中创建了一个**Sequence**,并向其中添加了一些**String**对象。然后通过调用`selector()`获取一个**Selector**,并用它在**Sequence**中移动和选择每一个元素。 最初看到**SequenceSelector**,可能会觉得它只不过是另一个内部类罢了。但请仔细观察它,注意方法`end()`,`current()`和`next()`都用到了**items**,这是一个引用,它并不是**SequenceSelector**的一部分,而是外部类中的一个**private**字段。然而内部类可以访问其外部类的方法和字段,就像自己拥有它们似的,这带来了很大的方便,就如前面的例子所示。 所以内部类自动拥有对其外部类所有成员的访问权。这是如何做到的呢?当某个外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外部类对象的引用。然后,在你访问此外部类的成员时,就是用那个引用来选择外部类的成员。幸运的是,编译器会帮你处理所有的细节,但你现在可以看到:内部类的对象只能在与其外部类的对象相关联的情况下才能被创建(就像你应该看到的,内部类是非**static**类时)。构建内部类对象时,需要一个指向其外部类对象的引用,如果编译器访问不到这个引用就会报错。不过绝大多数时候这都无需程序员操心。