Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
31
Добавлен:
27.03.2015
Размер:
168.96 Кб
Скачать

Нестатические внутренние классы-члены

Декларируются внутри основного класса, ассоциируются с экземпляром этого класса. В отличие от статических внутренних классов-членов , имеют доступ к членам внешнего класса. Не могут содержать определения статических полей, методов и классов, но могут их наследовать. Пример определения нестатического внутреннего класса:

class OuterClass( ) {

 

public OuterClass( ) { }

 

private int outerField;

 

class InnerClass {

 

int getOuterField(){

 

return OuterClass.this.outerField;

// здесь ошибки нет

}

 

}

 

}

 

Нестатических внутренних интерфейсов быть не может. Объявление вида public class OuterClass {

public interface ImNonStaticInterface { ... }

}

будет интерпретироваться так: public class OuterClass {

public static interface ImNonStaticInterface { ... }

}

Применение нестатических внутренних классов

Пусть есть класс Users, используемый, например, для управления доступом пользователей к данным веб-сайта:

public class Users {

...

public class Query { private Query( ) { ... }

public void setLogin( String login ) { ... } public void setCreationDate( Date date ) { ... } public List<User> list( ) { ... }

public User single( ) { ... }

}

public Query createQuery( ) { return new Query( );

}

}

Внутренний класс Query предназначен для поиска пользователей по заданным параметрам. Класс Query может инкапсулировать в себе, например, работу с базой данных. При этом он имеет доступ к состоянию экземпляра своего внешнего класса Users.

Пример клиентского кода:

Users.Query query = users.createQuery( ); query.setCreationDate( currentDate ); List<User> user = query.list( );

Локальные классы

Локальные классы объявляются и используются внутри методов обрамляющего класса и, соответственно, не являются его членами. Вот пример:

public class Handler {

public void handle(String requestPath) { // обработка строки запроса в веб-сервере class Path { // класс специфической обработки строки

List<String> parts = new ArrayList<String>(); String path = "/";

Path(String path) {

if (path == null) return; this.path = path;

for (String s : path.split("/")) if (s.trim().length() > 0) this.parts.add(s);

}

int size() { return parts.size(); }

String get(int i) { return i > this.parts.size() - 1 ? null : this.parts.get(i); } boolean startsWith(String s) { return path.startsWith(s); }

}

Path path = new Path(requestPath);

if (path.startsWith("/page")) { String pageId = path.get(1); ... }

if (path.startsWith("/post")) { String categoryId = path.get(1); String postId = path.get(2);

... }

... }

}

Локальные классы Ограничения

Как и классы-члены, локальные классы ассоциируются с экземпляром обрамляющего класса и имеют доступ ко всем его полям и методам.

Кроме этого, локальный класс может обращаться к локальным переменным и параметрам метода, в котором он декларирован, но только в том случае, если они объявлены с модификатором final. Причина состоит в том, что время жизни экземпляра локального класса может превышать время жизни метода, в котором он декларирован (точнее – времени жизни экземпляра обрамляющего класса).

Поэтому для экземпляра локального класса компилятором создаются его собственные копии всех тех переменных, с которыми экземпляр работает. А идентичность значения переменной и ее копии может быть обеспечена только в том случае, если она объявлена с модификатором final.

На локальные классы есть ограничения:

они видны только в пределах блока, в котором объявлены;

они не могут быть объявлены как private, public, protected или static;

они не могут иметь внутри себя статических объявлений (полей, методов, классов); исключением являются константы (static final);

локальный класс не может называться точно так же, как обрамляющий его класс.

Анонимные классы

Анонимные классы – это локальные классы, объявляемые внутри выражений без явного указания имени нового класса.

Классический пример создания и использования анонимного класса: new Thread( new Runnable() {

public void run() {

 

...

// это тело анонимного класса

}

 

}).start();

// символы } и ) должны быть записаны в одной строке

Здесь на основании анонимного класса создается и запускается с помощью метода start класса Thread новый поток управления.

Синтаксис создания анонимного класса состоит в использовании операции new с именем класса или интерфейса и телом создаваемого анонимного класса, заключенным в фигурные скобки.

Если указано имя базового класса, то создаваемый анонимный класс будет его подклассом.

Если указано имя интерфейса, то анонимный класс будет подклассом класса java.lang.Object и должен содержать реализацию всех методов интерфейса.

Анонимные классы

Кроме всех ограничений, накладываемых на локальные классы, для анонимных классов есть еще одно: у такого класса не может быть явно определенных конструкторов (поскольку к него нет имени). Поэтому для анонимного класса компилятор всегда строит конструктор по умолчанию без аргументов.

Однако инициализаторы у таких классов могут быть. На этом основан следующий пример использования анонимного класса:

import java.util.List; import java.util.ArrayList;

public class Test {

public static void main( String[ ] args ) { List<String> values = new ArrayList<String>( ) {{

add( "one" ); add( "two" ); add( "three" );

}};

for (String value : values) {

}

} System.out.println(value);

}

//это блок-инициализатор

//анонимного класса,

//унаследовавшего все методы,

//в том числе add от ArrayList

one two three

Анонимные классы

Анонимные классы имеет смысл использовать в тех случаях, когда:

тело класса является очень коротким и

нужен только один экземпляр класса и

имя класса не важно и не облегчает понимание кода.

Один из таких случаев типичен для обработки событий при реализации пользовательского интерфейса и используется очень широко. Пример:

JFrame myFrame = new JFrame( );

myFrame.addWindowListener( new java.awt.event.WindowAdapter( ) { public void windowClosing( java.awt.event.WindowEvent evt ) {

System.exit( 0 );

}

});

Здесь создается анонимный класс, расширяющий класс-адаптер java.awt.event.WindowAdapter, реализующий как пустые все 7 методов интерфейса java.awt.event.WindowListener. Анонимный класс этого примера замещает пустой метод windowClosing собственной реализацией, наследуя все

остальные пустые методы.

При возникновении события «закрытие окна» будет вызван метод windowClosing анонимного класса, что приведет к завершению программы.

Массивы (1)

Массивы в языке Java относятся к ссылочным типам и определяются способом, характерным для ссылочных типов. Полное определение включает три составных части.

Объявление. Содержит имя типа элементов массива, сопровождаемое парами квадратных скобок, и имя переменной (скобки могут быть указаны при имени переменной):

double[ ] currentBalance; String methodArgs[ ];

TailPosition[ ] tailPositions[ ]; // так объявлять массивы можно, но не рекомендуется float airPressure[ ][ ][ ];

Создание. Выполняется явно или неявно вызываемой операцией new, которая создает экземпляр специального класса, выделяет для него участок памяти нужного размера, инициализирует все элементы массива стандартным начальным значением для заданного типа элементов и возвращает указатель на экземпляр:

currentBalance = new double[ 10 ]; methodArgs = new String[ argsCount ];

tailPosition = new TailPosition[ rows ][ columns ]; airPressure = new float[ domainWidth ][ domainHeight ][ 10 ];

Объявление и создание массивов могут быть объединены: double[ ] currentBalance = new double[ 10 ];

String[ ] methodArgs = new String[ argsCount ];

TailPosition[ ] tailPosition[ ] = new TailPosition[ rows ][ columns ];

float[ ][ ][ ] airPressure = new float[ domainWidth ][ domainHeight ][ 10 ];

Массивы (2)

При создании многомерного массива обязательно указывать только значение самой левой (или нескольких левых) границы изменения индексов:

int arrayOfTerms[ ][ ][ ] = new int[ 10 ][ ][ ];

// допустимо, можно и [ 10 ][ 12 ][ ];

int arrayOfTerms[ ][ ][ ] = new int[ 10 ][ ][ 12 ];

// не допустимо!!!

Неявный вызов операции new может выполняться при определении массива с использованием третьей составной части - инициализации.

Инициализация. Установка начальных значений элементов массива, отличающихся от стандартных, может быть выполнена так:

double[ ] currentBalance = new double[ ] { -1.2, 5.27, 0, 0.7, 252, 18.1, 22, 3.64, 0, 99.73}; Или так:

double[ ] currentBalance = { -1.2, 165.27, 0, 9891.73, 252, 1850.1, 22, 643.64, 0, 0};

Важно помнить, что любые операции инициализации выполняются не компилятором, а виртуальной машиной. Соответственно, и первая и вторая приведенная здесь инициализация на самом деле компилятором превращается в такую последовательность операторов:

double[ ] currentBalance = new double[ 10 ]; currentBalance[0] = -1.2;

currentBalance[1] = 5.27;

currentBalance[9] = 99.73;

Создание с инициализацией, но без объявления, может быть использовано для передачи безымянного массива в качестве аргумента метода, например:

int response = alert.askQuestion( "Сохранить файл?" , new String[ ] { "Yes", "No"});

Массивы (3)

Однажды созданный массив нельзя уменьшить или увеличить в размерах. Можно создать другой массив и «перещелкнуть» ссылку на него:

currentBalance = new double[ 12 ]; // предыдущий массив становится мусором

Любой массив всегда содержит целочисленную константу length. Оператор:

System.out.println( currentBalance.length );

выведет на консоль значение 12. Нумерация элементов массива ведется с 0.

Виртуальная машина контролирует значения индексов при любом доступе к массиву. В случае выхода индекса за пределы диапазона 0 – (length-1) выбрасывается непроверяемое исключение java.lang.ArrayIndexOutofBoundsException.

Многомерные массивы в Java на самом деле являются одномерными массивами, элементы которых содержат экземпляры специального класса-массива меньшей размерности. Поэтому многомерные массивы не обязательно должны быть прямоугольными. Например, можно создать массив «таблица умножения»:

int[ ][ ] multiplicaionTable = {

{0 },

{0, 1 },

{0, 2, 4 },

{0, 3, 6, 9 },

};

Соседние файлы в папке Презентации по Java