Подтвердить что ты не робот

Хорошие причины запретить наследование Java?

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

4b9b3361

Ответ 1

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

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

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

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

  • Классы отмечены final

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

Цель создания финального класса:

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

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

Ответ 6

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

См. "Эффективные Java-версии 2-й редакции" 16 и 17 или мое сообщение в блоге "Налог на наследство" .

Ответ 7

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

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

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

 String blah = someOtherString;

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Ответ 11

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