Внутренние классы в методе и контексте
То, что Вы видели в предыдущем разделе - типичное использование для внутренних классов. В основном же, тот код, который Вы будете писать и читать, используя внутренние классы должен быть ясным и простым. Эти классы должны быть легки для понимания. Тем не менее, проектировка внутренних классов вами вполне доведена до конца, но существует еще и некоторое число других, более запутанных способов создания внутренних классов. Оные Вы можете использовать по собственному желанию: внутренний класс может быть создан внутри метода или даже в случайном контексте. Вот две причины побуждающие делать это:
В следующих примерах, предыдущий код будет изменен для получения следующих "результатов":
Хотя это и обычный класс с реализацией, но Wrapping так же используется и в качестве общего интерфейса к его производным классам:
//: c08:Wrapping.java
public class Wrapping { private int i; public Wrapping(int x) { i = x; } public int value() { return i; } } ///:~
Вы должны знать, что у Wrapping есть конструктор, требующий аргумента. Это сделано для того, что бы было немножко поинтереснее.
В первом примере показывается создание целого класса внутри контекста метода (вместо контекста другого класса):
//: c08:Parcel4.java
// Вложенность класса внутри метода.
public class Parcel4 { public Destination dest(String s) { class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel4 p = new Parcel4(); Destination d = p.dest("Tanzania"); } } ///:~
Класс PDestination скорее часть dest( ) чем Parcel4. ( Так же заметьте, что Вы можете использовать идентификатор класса PDestination для внутреннего класса внутри каждого класса в одной и той же поддиректории без конфликта имен.) Следовательно, PDestination не может быть доступен снаружи dest( ). Заметьте, что приведение к базовому типу происходит в операторе возврата, ничего не попадает наружу из dest( ), кроме ссылки на Destination, т.е. на базовый класс. Естественно, факт того, что имя класса PDestination помещено внутри dest( ) еще не означает, что PDestination не правильный объект, который возвращает dest( ).
Следующий пример покажет вам, как Вы можете вложить внутренний класс внутри любого случайного контекста:
//: c08:Parcel5.java
// Вложенный класс внутри контекста.
public class Parcel5 { private void internalTracking(boolean b) { if(b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } // Нельзя его здесь использовать! Вне контекста:
//! TrackingSlip ts = new TrackingSlip("x");
} public void track() { internalTracking(true); } public static void main(String[] args) { Parcel5 p = new Parcel5(); p.track(); } } ///:~
Класс TrackingSlip помещен внутри контекста, а так же внутри оператора if. Но это не означает, что этот класс условно создается, он будет скомпилирован вместе с остальным кодом. Тем не менее он не будет доступен снаружи контекста, в котором он был объявлен. Кроме этой особенности он выглядит точно так же, как обычный класс.