Есть ли какой-либо другой способ остановить наследование класса, кроме объявления его окончательным или объявления его конструктора закрытым?
не могли бы вы объяснить, почему вы пытаетесь избежать использования последнего ключевого слова?
Вероятно, потому что здесь задействован фреймворк, создающий подклассы.
я просто пытался найти другие способы ... они дают интересные результаты ... мне было просто любопытно
... в этом случае невозможно остановить наследование, которое также допускает наследование. :-)
@dtsazza Есть вещи, которые может делать фреймворк, которые вы обычно не позволяете делать пользовательскому коду; фреймворк может изменить уровень защиты частного конструктора во время выполнения. AFIK вы не можете связываться с финалом, хотя ...
@dtsazza В сущности, фреймворк может иметь отношение «не делайте этого дома, дети».
Почему все отвечают: «Используйте final», когда в самом вопросе говорится: «Кроме final ...». Я думаю, что они правы, но дело в том, что вопрос не в этом. Я думаю, мы привыкли к «субъективным и аргументированным» вопросам, в которых упускаем из виду суть.
Вопрос очень ясный, и ответ не является настоящим ответом, но все же получает одобрение. Разве мы не должны использовать stackoverflow.com/questions/318503/… :)
это вопросы собеседования / класса?




Комментарий
//Do not inherit please
Я действительно считаю, что это лучшее решение на свете. Вы даже можете описать, почему его нельзя наследовать.
Final был создан для решения этой проблемы.
Я бы сказал, что это обычно дурной тон. Хотя почти всегда есть случаи, когда что-то действительно, я бы сказал, что прекращение наследования в объектно-ориентированном мире обычно не является хорошей идеей. Прочтите Принцип открытости закрыт и здесь. Защитите свою функциональность, но не делайте невозможной для человека, который приходит и поддерживает ее ...
Наследование сильно переоценено. Если вы не разрабатываете свой класс для создания подклассов, вам лучше этого избегать.
+1, держу пари, что дядя Боб Мартин знает об ОО больше, чем кто-либо здесь.
+1 к комментарию Петра. Как я уже говорил в другом месте (много раз!), Я бы хотел, чтобы классы были запечатаны (C#) / final (Java) по умолчанию. Наследование - это здорово, когда оно вам действительно нужно, но это может быть проблемой, если вы просто используете его, не задумываясь об этом.
«Оформляйте и оформляйте документы на наследство, иначе запретите». - Джош Блох, Effective Java Item 17
Прочтите книгу Майкла Фезера «Эффективная работа с устаревшим кодом». Он помог мне пройти через ряд проектов на старых объектах, и такие вещи, как классы и методы, которых нельзя трогать, являются основными болевыми точками. Даже если вы этого не планировали, функция XYZ понадобится. Все о проверке будущего ...
@Mark G: наследование ограничивает изменения в реализации, поэтому я вообще не считаю, что это нужно для будущего. Это пределы будущих изменений, а не их разрешения.
@Jon Skeet: По моему опыту, я просто не видел этого. Возьмите любой из диалогов в .NET BCL (Открыть / Сохранить / Печать), ничего страшного с ними сделать нельзя, потому что они запечатаны, и это большая проблема. Но это обсуждение, вероятно, должно быть в другом вопросе с тегом «Субъективный».
Еще два варианта:
сделайте каждый метод окончательным, чтобы люди не могли их переопределить. Таким образом вы избегаете случайного вызова методов из подкласса. Однако это не останавливает создание подклассов.
поставить отметку в конструкторе для класса:
if (this.getClass() != MyClass.class) {
throw new RuntimeException("Subclasses not allowed");
}
Тогда никто не сможет создать подкласс вашего класса.
(Не то чтобы я предлагал использовать эти методы, это просто пришло мне в голову. Я бы использовал конечный класс и / или частный конструктор)
Крысы, я как раз собирался сам опубликовать исключение.
За исключением случаев, когда метод finalize переопределяется, экземпляр может быть восстановлен.
+1 Я не думал, что на этот вопрос будет реальный ответ, но я думаю, это так близко, как вы собираетесь получить.
@Chris Lively: Конструктор из суперкласса должен вызываться всегда. Вы можете «переопределить» конструктор (хотя не существует такой вещи, как переопределяющий конструктор, поскольку конструктор не наследуется), но вы не можете «пропустить» конструктор из суперкласса.
Использование final - канонический способ.
public final class FinalClass {
// Class definition
}
Если вы хотите предотвратить переопределение отдельных методов, вы можете вместо этого объявить их как final. (Я просто догадываюсь, почему вам нужно хочу, чтобы не делать весь класс окончательным.)
Причины, похожие на java.lang.String, я бы предположил.
Используйте комментарий:
// do not inherit
Используйте комментарий javadoc
Используйте проверку времени выполнения в конструкторе класса:
if (this.getClass() != MyClass.class) {
throw new RuntimeException("Subclasses not allowed");
}
Идея комментария действительно не имеет особого смысла. Комментарий JavaDoc имеет гораздо больше смысла, но все же не надежен.
Сделайте ваши конструкторы частными и предоставьте фабричные функции для создания экземпляров.
Это может быть особенно полезно, если вы хотите выбрать подходящую реализацию из нескольких, но не хотите разрешать произвольное создание подклассов, как в
abstract class Matrix {
public static Matrix fromDoubleArray(double[][] elemens) {
if (isSparse(elements)) {
return new SparseMatrix(elements);
} else {
return new DenseMatrix(elements);
}
}
private Matrix() { ... } // Even though it's private, inner sub-classes can still use it
private static class SparseMatrix extends Matrix { ... }
}
Без использования последнего класса вы можете сделать все конструкторы закрытыми:
public class A {
private A() {} //Overriding default constructor of Java
}
Что, хотя также сделает этот класс абстрактным, запретив создание объекта этого класса, но поскольку для любого наследования требуется super(); в конструкторе, и поскольку конструктор является частным, ошибка компиляции будет максимальной, которую вы можете получить при попытке унаследовать этот класс.
Тем не менее, я бы рекомендовал использовать final, так как это меньше кода и включает возможность создания объектов.
Что не так с финалом?