Связь с внешним классом
Поскольку, внутренний класс предоставлялся только для целей скрытия имени и кода, что несомненно помогает, но все же не является всеобъемлющей особенностью внутренних классов. Тем не менее, имеется еще один способ использования внутренних классов. Когда Вы создаете внутренний класс, объект этого внутреннего класса имеет связь с окружающим его объектом и поэтому он имеет доступ к элементам этого объекта, без каких либо специальных предикатов. В дополнение внутренние классы имеют права доступа ко всем элементам окружающего его класса[40]. Нижеследующий пример как раз это и показывает:
//: c08:Sequence.java
// Поддержка последовательности объектов.
interface Selector { boolean end(); Object current(); void next(); }
public class Sequence { private Object[] obs; private int next = 0; public Sequence(int size) { obs = new Object[size]; } public void add(Object x) { if(next < obs.length) { obs[next] = x; next++; } } private class SSelector implements Selector { int i = 0; public boolean end() { return i == obs.length; } public Object current() { return obs[i]; } public void next() { if(i < obs.length) i++; } } public Selector getSelector() { return new SSelector(); } public static void main(String[] args) { Sequence s = new Sequence(10); for(int i = 0; i < 10; i++) s.add(Integer.toString(i)); Selector sl = s.getSelector(); while(!sl.end()) { System.out.println(sl.current()); sl.next(); } } } ///:~
Sequence - просто массив с фиксированным размером, с элементами типа Object, с классом обернутым вокруг него. Вы вызываете метод add( ) для добавления нового Object-а в конец последовательности (если там еще есть место). Для выборки каждого из объекта в Sequence, имеется интерфейс Selector, который позволяет так же вам узнать, что вы в конце end( ), для просмотра текущего current( ) Object-а, и для перехода на следующий next( ) Object в последовательности Sequence. Поскольку Selector - interface, многие другие классы могут реализовать его по своему собственному усмотрению, а так же многие методы могут получать этот интерфейс как аргумент, в порядке создания наследуемого кода.
Здесь, SSelector - private класс, который предоставляет функциональность Selector. В main( ), Вы можете видеть создание Sequence, следующее за добавлением объектов String. Затем Selector создается путем вызова getSelector( ) и при его же помощи можно перемещаться по Sequence выбирая каждый из элементов.
На первый взгляд, создание SSelector выглядит, как просто создание другого внутреннего класса. Но просмотрите его более внимательно. Заметьте, что каждый из методов end( ), current( ) и next( ) ссылаются на obs, который является ссылкой и не является частью SSelector, но он заменяет private поле в окружающем классе. Тем не менее, внутренний класс может получить доступ к методам и полям окружающего класса, как если бы они были его собственными полями.
Так что внутренний класс имеет автоматически доступ к элементам окружающего его класса. А как же тогда такое происходит? Внутренний класс должен хранить ссылку на объект окружающего класса, ответственный за его создание. Потом, когда Вы будете ссылаться на элемент окружающего класса, то будет использована эта скрытая ссылка, что бы выбрать этот элемент. К счастью, компилятор заботится обо всех этих деталях вместо вас, но Вы все равно должны понимать, что этот объект внутреннего класса может быть создан только в соединении с объектом окружающего класса. Создание объекта внутреннего класса требует ссылки на объект окружающего его класса и компилятор выдаст сообщение об ошибке, если он не сможет получить доступ к этой ссылке. Наиболее часто это случается без какого либо вмешательства в эту часть программистом.