© 2008 Наталия Македа
Все материалы блога защищены авторским правом. Любая перепечатка или использование материалов этого блога в коммерческих целях возможна лишь с письменного согласия автора. При некоммерческом использовании ссылка на блог обязательна.

вторник, 13 октября 2009 г.

abstract (Выпуск 18)

Модификатор abstract применяется только для классов и методов.

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

Абстрактные классы перекладывают имплементацию методов на "плечи" своих подклассов. Рассмотрим, к примеру, рисунок ниже:

Разработчик класса Animal решил, что все животные должны иметь метод travel(). Поскольку каждое животное перемещается по-своему, то невозможно заимплементировать этот метод уникальным образом и просто наследовать этот метод в подклассы. Поэтому метод travel() объявлен с модификатором abstract следующим образом:

abstract void travel();

Обратите внимание на точку с запятой (а не фигурных скобок) в конце объявления метода. Фигурные скобки вместе с телом метода отдаются на усмотрение подклассов. Суперкласс обеспечивает только сигнатуру метода, которой должны придерживаться подклассы. При этом подклассы класса Animal должны или заимплементировать метод travel() или опять объявить его абстрактным. Во втором случае имплементация абстрактного метода опять переносится в подклассы подкласса.

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

Класс рекомендуется объявлять абстрактным, если:

  • В классе есть абстрактные методы.
  • Класс наследует абстрактные методы (от абстрактного суперкласса) и не предоставляет имплементации для всех унаследованных абстрактных методов.
  • Класс имплементирует интрефейс но не предоставляет имплементации для всех методов интерфейса.

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

Таким образом, можификатор abstract можно считать противоположностью модификатору final. Финальный класс не может иметь подклассов. Абстрактный класс должен иметь подклассы.


Читать далее!

понедельник, 12 октября 2009 г.

final (Выпуск 18)

Модификатор final может применяться к классам, методам и переменным. При этом его конкретное значение зависит от контекста. Но в общем модификатор final означает, что элемент не может быть модифицирован, изменён.

В частности, final класс не может иметь подклассов. Например, следующий код просто не откомпилируется, потому что java.lang.Math имеет модификатор final:

class SubMath extends java.lang.Math { }

Получаем ошибку компиляции: "Can’t subclass final classes." ("Невозможно создать подкласс от класса final")

Final переменная не может принимать значение, которое отличается от того, что было присвоено при инициализации. Поэтому в Java переменные с модификатором final играют роль const в C++ и #define в С. Например в классе java.lang.Math есть переменная с модификатором final типа double, которая называется PI. Очевидно, что число пи не должно изменяться по прихоти программиста.

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

1. class Walrus {
2. int weight;
3. Walrus(int w) { weight = w; }
4. }
5.
6. class Tester {
7. final Walrus w1 = new Walrus(1500);
8. void test() {
9. w1 = new Walrus(1400); // Illegal
10. w1.weight = 1800; // Legal
11. }
12. }

Обратите внимание, как в строке 7 объект w1 был объявлен с модификатором final. Именно поэтому в строке 9 выполняется недопустимая операция создания нового указателя на объект. Хотя в строке 10 мы можем изменить значение некоторых полей объекта.

Иными словами:

  • Нельзя менять ссылку на объект, то есть пересоздавать объект.
  • Можно изменять значения полей.

Наконец, final метод не может быть переопределён (overriden). Например, следующий код не откомпилируется:

1. class Mammal {
2. final void getAround() { }
3. }
4.
5. class Dolphin extends Mammal {
6. void getAround() { }
7. }

Дельфины плавают совершенно по-другому в отличие от большинства млекопитающих. Поэтому имеет смысл переопределить метод унаследованный метод getAround(). Но этот метод final, поэтому в 6 строке мы получим ошибку компиляции "Final methods can’t be overridden." (Финальные методы не могут быть переопределены)


Читать далее!