Хорошие причины запретить наследование в Java? - PullRequest
154 голосов
/ 20 октября 2008

Каковы веские причины для запрета наследования в Java, например, с использованием конечных классов или классов с использованием одного частного конструктора без параметров? Каковы веские причины сделать метод окончательным?

Ответы [ 11 ]

165 голосов
/ 20 октября 2008

Ваша лучшая ссылка здесь - это пункт 19 из превосходной книги Джошуа Блоха «Эффективная Ява» под названием «Дизайн и документ для наследования, или же запретить его». (Это пункт 17 во втором издании и пункт 15 в первом издании.) Вы действительно должны прочитать его, но я подведу итоги.

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

Поэтому классы должны быть двух видов:

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

  2. Классы отмечены финал

Если вы пишете чисто внутренний код, это может быть немного излишним. Однако дополнительные усилия по добавлению пяти символов в файл класса очень малы. Если вы пишете только для внутреннего потребления, будущий кодер всегда может удалить «финал» - вы можете думать об этом как о предупреждении «этот класс не был разработан с учетом наследования».

21 голосов
/ 20 октября 2008

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

17 голосов
/ 20 октября 2008

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

13 голосов
/ 13 декабря 2013

Существует 3 варианта использования, в которых вы можете использовать финальные методы.

  1. Во избежание переопределения производного класса определенной функциональности базового класса.
  2. Это для целей безопасности, где базовый класс предоставляет некоторые важные базовые функциональные возможности платформы, где производный класс не должен ее изменять.
  3. Финальные методы работают быстрее, чем методы экземпляра, так как в финальных и закрытых методах концепция виртуальной таблицы не используется Поэтому, когда есть возможность, попробуйте использовать финальные методы.

Цель участия в выпускном занятии:

Чтобы никто не мог расширить эти классы и изменить их поведение.

Например: класс Wrapper Integer является конечным классом. Если этот класс не является окончательным, то любой может расширить Integer в свой собственный класс и изменить базовое поведение целочисленного класса. Чтобы избежать этого, java сделал все классы-обёртки финальными.

12 голосов
/ 20 октября 2008

возможно, вы захотите сделать неизменяемые объекты (http://en.wikipedia.org/wiki/Immutable_object),, возможно, вы захотите создать синглтон (http://en.wikipedia.org/wiki/Singleton_pattern),) или можете запретить кому-либо переопределять метод по соображениям эффективности, безопасности или безопасность.

6 голосов
/ 20 октября 2008

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

См. Пункты «Эффективное Java 2-е издание», пункты 16 и 17, или мой пост в блоге «Налог на наследство» .

4 голосов
/ 20 октября 2008

Хммм ... Я могу думать о двух вещах:

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

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

 String blah = someOtherString;

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

1 голос
/ 20 октября 2008

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

1 голос
/ 20 октября 2008

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

1 голос
/ 20 октября 2008

Чтобы люди не могли делать то, что могло бы сбить их с толку и окружающих. Представьте себе физическую библиотеку, в которой у вас есть определенные константы или расчеты. Без использования ключевого слова final кто-то может прийти и переопределить базовые вычисления или константы, которые НИКОГДА не должны меняться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...