Философия Java

Внутренние классы в методе и контексте


То, что Вы видели в предыдущем разделе - типичное использование для внутренних классов. В основном же, тот код, который Вы будете писать и читать, используя внутренние классы должен быть ясным и простым. Эти классы должны быть легки для понимания. Тем не менее, проектировка внутренних классов вами вполне доведена до конца, но существует еще и некоторое число других, более запутанных способов создания внутренних классов. Оные Вы можете использовать по собственному желанию: внутренний класс может быть создан внутри метода или даже в случайном контексте. Вот две причины побуждающие делать это:

  • Как было показано предварительно, Вы реализуете интерфейс какого-то типа, так что Вы можете создать и вернуть ссылку.
  • Вы решаете какую-то проблему и хотите создать класс, который эту проблему исправляет, но Вы не хотите, что бы этот класс был доступен для кого-то еще.
  • В следующих примерах, предыдущий код будет изменен для получения следующих "результатов":

  • Класс определен в методе
  • Класс определен в контексте внутри метода
  • Анонимный класс реализует интерфейс
  • Анонимный класс расширяет класс, который имеет конструктор не по умолчанию
  • Анонимный класс, осуществляющий инициализацию полей
  • Анонимный класс, который осуществляет создание, используя инициализацию экземпляра (анонимный внутренний класс не может быть с конструктором)
  • Хотя это и обычный класс с реализацией, но 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. Но это не означает, что этот класс условно создается, он будет скомпилирован вместе с остальным кодом. Тем не менее он не будет доступен снаружи контекста, в котором он был объявлен. Кроме этой особенности он выглядит точно так же, как обычный класс.


    Содержание раздела