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


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

11 145

11 ответов:

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

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

классы должны поэтому прийти два вида :

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

  2. классы С пометкой финал

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

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

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

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

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

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

цель создания класса final:

Так что ни одно тело не может расширить эти классы и изменить их поведение.

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

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

см. эффективные элементы Java 2nd edition 16 и 17 или мой пост в блоге "Налог На Наследство".

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

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

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

 String blah = someOtherString;

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

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

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

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

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