Использование ключевого слова Final с наследованием в Java

Хотя один из в Java сильными сторонами является понятие наследования, в котором учебный класс может происходить от другого, иногда желательно предотвратить наследование другим классом. Чтобы предотвратить наследование, используйте ключевое слово «final» при создании класса.

Например, если класс, вероятно, будет использоваться другими программистами, вы можете предотвратить наследование, если какие-либо созданные подклассы могут вызвать проблемы. Типичным примером является Струнный класс. Если мы хотим создать подкласс String:

открытый класс MyString extends String {
}

Мы столкнемся с этой ошибкой:

 не может наследовать от окончательного java.lang. строка 

Дизайнеры класса String поняли, что он не является кандидатом на наследование, и помешали его расширению.

Зачем предотвращать наследование?

Основная причина, чтобы предотвратить наследование чтобы убедиться, что поведение класса не искажено подклассом.

Предположим, у нас есть класс Account и подкласс, расширяющий его, OverdraftAccount. Класс Account имеет метод getBalance ():

instagram viewer
 public double getBalance ()

{

 вернуть этот баланс

 } 

На данный момент в нашем обсуждении подкласс OverdraftAccount не переопределил этот метод.

(Заметка: Для другого обсуждения, использующего классы Account и OverdraftAccount, посмотрите, как подкласс может рассматриваться как суперкласс).

Давайте создадим экземпляр каждого из классов Account и OverdraftAccount:

 Аккаунт bobsAccount = новый Аккаунт (10);

 bobsAccount.depositMoney (50);

 OverdraftAccount jimsAccount = новый OverdraftAccount (15.05,500,05);

 jimsAccount.depositMoney (50);

 // создаем массив объектов Account

 // мы можем включить jimsAccount, потому что мы 

 // хочу рассматривать только как объект Account

 Account [] account = {bobsAccount, jimsAccount};


 // для каждой учетной записи в массиве отображаем баланс

 для (Аккаунт а: аккаунты)

 {

 System.out.printf («Баланс% .2f% n», a.getBalance ());

 }

 Выход:

 Баланс 60,00

 Баланс 65.05 

Здесь все работает так, как ожидалось. Но что, если OverdraftAccount переопределяет метод getBalance ()? Ничто не мешает ему делать что-то вроде этого:

 открытый класс OverdraftAccount расширяет счет {


 приватный двойной овердрафтLimit;

 приватный двойной овердрафтFee;


 // остальная часть определения класса не включена


 public double getBalance ()

 {

 возврат 25.00;

 }

 } 

Если приведенный выше пример кода будет выполнен снова, выходные данные будут другими, поскольку для класса jimsAccount вызывается поведение getBalance () в классе OverdraftAccount:

 Выход:

 Баланс 60,00

 Баланс 25.00 

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

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

Как предотвратить наследование

Чтобы остановить расширение класса, объявление класса должно явно сказать, что оно не может быть унаследовано. Это достигается с помощью ключевого слова "final":

 открытый финальный класс


 } 

Это означает, что класс Account не может быть суперклассом, а класс OverdraftAccount больше не может быть его подклассом.

Иногда вы можете захотеть ограничить только определенное поведение суперкласса, чтобы избежать искажения подклассом. Например, OverdraftAccount все еще может быть подклассом Account, но его следует избегать переопределения метода getBalance ().

В этом случае используйте ключевое слово «final» в объявлении метода:

 Public Class Account {


 личный двойной баланс;


 // остальная часть определения класса не включена


 публичный финальный двойной getBalance ()

 {

 вернуть этот баланс

 } 

 } 

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