Смекни!
smekni.com

Общие представления о языке Java 5 (стр. 64 из 68)

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

Внутренние (inner) классы

Внутренний класс задаётся так же, как вложенный, но только без модификатора static перед именем этого класса:

class ИмяВнешнегоКласса{

тело внешнего класса

class ИмяВнутреннегоКласса{

тело внутреннего класса

}

продолжение тела внешнего класса

}

Для внутренних классов экземпляры создаются через имя объекта внешнего класса, что принципиально отличает их от обычных и вложенных классов.

Синтаксис таков:

Сначала идёт создание экземпляра внешнего класса:

ИмяВнешнегоКласса имяОбъекта = new ИмяВнешнегоКласса(параметры);

Затем создаётся нужное число экземпляров внутреннего класса:

ИмяВнешнегоКласса.ИмяВнутреннегоКласса имя1 =

имяОбъекта.new ИмяВнутреннегоКласса(параметры);

ИмяВнешнегоКласса.ИмяВнутреннегоКласса имя2 =

имяОбъекта.new ИмяВнутреннегоКласса(параметры);

и так далее.

Достаточно часто из внутреннего класса необходимо обратиться к объекту внешнего класса. Такое обращение идёт через имя внешнего класса и ссылку this на текущий объект:

ИмяВнешнегоКласса.this

- это ссылка на внешний объект (его естественно назвать родительским объектом). А доступ к полю или методу внешнего объекта в этом случае, естественно, идёт так:

ИмяВнешнегоКласса.this.имяПоля

ИмяВнешнегоКласса.this.имяМетода(список параметров).

К сожалению, в Java, в отличие от языка JavaScript, нет зарезервированного слова parent для обращения к родительскому объекту. Будем надеяться, что в дальнейшем в java будет введён этот гораздо более читаемый и удобный способ обращения к родителю.

Пример работы с внутренними классами:

package java_gui_example;

public class OuterClass {

int a=5;

public OuterClass() {

}

public class InnerClass{

int x=1,y=1;

public class InnerClass2 {

int z=0;

InnerClass2(){

System.out.println("InnerClass2 object created");

};

void printParentClassNames(){

System.out.println("InnerClass.this.x="+InnerClass.this.x);

System.out.println("OuterClass.this.a="+OuterClass.this.a);

}

}

}

InnerClass inner1;

InnerClass.InnerClass2 inner2;

public void createInner() {

inner1=this.new InnerClass();

inner2=inner1.new InnerClass2();

System.out.println("inner1 name="+inner1.getClass().getName());

System.out.println("inner1 canonical name="+

inner1.getClass().getCanonicalName());

}

}

Если в приложении задать переменную типа OuterClass и создать соответствующий объект

OuterClass outer1=new OuterClass();

то после этого можно создать объекты внутренних классов:

outer1.createInner();

Доступ к внешним объектам иллюстрируется при вызове метода

outer1.inner2.printParentClassNames();

Заметим, что при создании внутреннего класса в приложении, а не в реализации класса OuterClass, вместо

InnerClass inner1=this.new InnerClass();

и

InnerClass.InnerClass2 inner2= inner1.new InnerClass2();

придётся написать

OuterClass.InnerClass inner3=outer1.new InnerClass();

OuterClass.InnerClass.InnerClass2 inner4=inner3.new InnerClass2();

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

Локальные (local) классы

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

class LocalClass1 {

public LocalClass1(){

System.out.println("LocalClass1 object created");

}

};

LocalClass1 local1=new LocalClass1();

Этот код можно вставить в любой метод. Например, в обработчик события нажатия на кнопку. Конечно, данный пример чисто иллюстративный.

Анонимные (anonimous) классы и обработчики событий

Анонимный (безымянный) класс объявляется без задания имени класса и переменных данного безымянного типа – задаётся только конструктор класса вместе с его реализацией. У анонимного класса может быть только один экземпляр, причём он создаётся сразу при объявлении класса. Поэтому перед объявлением анонимного класса следует ставить оператор new. Анонимный класс должен быть наследником какого-либо класса или интерфейса, и соответствующий тип должен быть указан перед списком параметров конструктора.

Синтаксис задания анонимного класса таков:

new ИмяПрародителя(список параметров конструктора) {

тело конструктора

}

Как уже говорилось, анонимные классы обычно используют в обработчиках событий, причём сама необходимость в таких классах, по мнению автора, вызвана неудачной организацией в Java работы с обработчиками событий.

Пример использования анонимного класса в “слушателе” события (о них речь пойдёт в следующем параграфе):

addMouseMotionListener(

new java.awt.event.MouseMotionAdapter(){

public void mouseDragged(java.awt.event.MouseEvent e){

System.out.println("Mouse dragged at: x="+

e.getX()+" y="+e.getY()

);

}

}

);

Анонимные (anonimous) классы и слушатели событий (listeners)

Событие в Java (будем называть его программным событием, или, сокращённо, просто событием) – это объект, возникающий при наступлении какого-либо события в реальном мире при взаимодействии с ним компьютера (будем называть его физическим событием). Например, физическим событием может быть нажатие на клавишу клавиатуры. При наступлении некоторых физических событий возникают программные события – создаются объекты, имеющие тип, зависящий от того, какое событие наступило. Обработчики событий – подпрограммы, которые выполняют некоторый код при наступлении программного события. Например, код, который будет выполнен при нажатии пользователем на кнопку jButton1 во время работы приложения.

В Java к каждому объекту, поддерживающему работу с неким событием, могут добавляться слушатели (listeners) событий этого типа – объекты-обработчики событий. Они являются экземплярами специальных классов Listeners, в которых заданы методы, реагирующие на соответствующие типы событий.

Классы и интерфейсы для работы с событиями заданы в пакетах java.awt, java.awt.event и javax.swing.event.

Важнейшие типы событий:

В пакете java.awt:

java.awt.AWTEvent – абстрактный класс, прародительский для всех классов событий.

В пакете java.awt.event:

ActionEvent – событие действия (как правило, нажатие).

AdjustmentEvent – изменение значения в линии прокрутки (для компонентов с линией прокрутки).

ComponentEvent – компонент переместился, изменил размер или видимость (visibility) -показался или был скрыт.

ContainerEvent – содержимое компонента-контейнера изменилось – какой-либо компонент был в него добавлен или из него убран.

FocusEvent – компонент получил или потерял фокус.

HierarchyEvent – изменение положения компонента в физической иерархии (иерархии агрегации). Например, удаление родительского компонента, смена компонентом родителя (перетаскивание с одного компонента на другой), и т.п.

InputEvent – произошло событие ввода. Базовый класс для классов событий ввода (KeyEvent, MouseEvent)

InputMethodEvent – произошло событие ввода. Содержит информацию об обрабатываемом тексте.

ItemEvent – событие, возникающее в случае, если пункт (item) был отмечен (selected) или с него была снята отметка (deselected).

KeyEvent – событие нажатия на клавишу.

MouseEvent – событие мыши.

PaintEvent – событие отрисовки. Служит для управления очередью событий и не может быть использовано для управления отрисовкой вместо методов paint или update.

TextEvent - событие, возникающее в случае, если текст в текстовом компоненте изменился.

WindowEvent – окно изменило статус (открылось, закрылось, максимизировалось, минимизировалось, получило фокус, потеряло фокус).

Также имеется большое количество событий в пакете javax.swing.event.

Для того, чтобы программа могла обработать событие какого-то типа, в приложение требуется добавить объект event listener (“слушатель события”) соответствующего типа. Этот тип - класс, который должен реализовать интерфейс слушателя, являющийся наследником интерфейса java.util.EventListener. Имя интерфейса слушателя обычно складывается из имени события и слова Listener.

Чтобы упростить реализацию интерфейсов, в Java для многих интерфейсов событий существуют так называемые адаптеры (adapters) – классы, в которых все необходимые методы интерфейсов слушателей уже реализованы в виде ничего не делающих заглушек. Так что в наследнике адаптера требуется только переопределение необходимых методов, не заботясь о реализации всех остальных. Перечислим важнейшие интерфейсы и адаптеры слушателей:

ActionEvent – ActionListener.

AdjustmentEvent – AdjustmentListener.

ComponentEvent – ComponentListener - ComponentAdapter.

ContainerEvent – ContainerListener - ContainerAdapter.

FocusEvent – FocusListener - FocusAdapter.

HierarchyEvent – HierarchyBoundsListener - HierarchyBoundsAdapter.

InputEvent – нет интерфейсов и адаптеров.

InputMethodEvent – InputMethodListener.

ItemEvent – ItemListener.

KeyEvent – KeyListener - KeyAdapter.

MouseEvent - MouseListener - MouseAdapter.

- MouseMotionListener - MouseMotionAdapter. По-английски motion – “движение”. Событие возникает при движении мыши.

- MouseWheelListener-MouseWheelAdapter. По-английски wheel – “колесо”. Событие возникает при прокручивании колёсика мыши.

PaintEvent – нет интерфейсов и адаптеров.

TextEvent – TextListener.

WindowEvent - WindowListener - WindowAdapter.

- WindowFocusListener. Событие возникает при получении или потере окном фокуса.

- WindowStateListener. Событие возникает при изменении состояния окна.

Все компоненты Swing являются потомками javax.swing.JComponent. А в этом классе заданы методы добавления к компоненту многих из упомянутых слушателей:

addComponentListener, addFocusListener и т.д. В классах компонентов, обладающих специфическими событиями, заданы методы добавления слушателей этих событий.

Повторим теперь код, приведённый в предыдущем параграфе, с разъяснениями:

addMouseMotionListener(

new java.awt.event.MouseMotionAdapter(){

public void mouseDragged(java.awt.event.MouseEvent e){

System.out.println("Mouse dragged at: x="+