Остановка наследования без использования final

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

Что не так с финалом?

lc. 16.01.2009 20:03

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

shsteimer 16.01.2009 20:14

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

krosenvold 16.01.2009 20:20

я просто пытался найти другие способы ... они дают интересные результаты ... мне было просто любопытно

shweta 16.01.2009 20:25

... в этом случае невозможно остановить наследование, которое также допускает наследование. :-)

Andrzej Doyle 16.01.2009 20:25

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

krosenvold 16.01.2009 20:30

@dtsazza В сущности, фреймворк может иметь отношение «не делайте этого дома, дети».

krosenvold 16.01.2009 20:33

Почему все отвечают: «Используйте final», когда в самом вопросе говорится: «Кроме final ...». Я думаю, что они правы, но дело в том, что вопрос не в этом. Я думаю, мы привыкли к «субъективным и аргументированным» вопросам, в которых упускаем из виду суть.

OscarRyz 16.01.2009 20:34

Вопрос очень ясный, и ответ не является настоящим ответом, но все же получает одобрение. Разве мы не должны использовать stackoverflow.com/questions/318503/… :)

OscarRyz 16.01.2009 20:35

это вопросы собеседования / класса?

Miserable Variable 16.01.2009 20:35
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
8
10
13 921
8

Ответы 8

Комментарий

//Do not inherit please

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

vava 16.01.2009 20:09

Final был создан для решения этой проблемы.

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

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

Peter Štibraný 16.01.2009 20:13

+1, держу пари, что дядя Боб Мартин знает об ОО больше, чем кто-либо здесь.

jcollum 16.01.2009 20:15

+1 к комментарию Петра. Как я уже говорил в другом месте (много раз!), Я бы хотел, чтобы классы были запечатаны (C#) / final (Java) по умолчанию. Наследование - это здорово, когда оно вам действительно нужно, но это может быть проблемой, если вы просто используете его, не задумываясь об этом.

Jon Skeet 16.01.2009 20:15

«Оформляйте и оформляйте документы на наследство, иначе запретите». - Джош Блох, Effective Java Item 17

Michael Myers 16.01.2009 20:17

Прочтите книгу Майкла Фезера «Эффективная работа с устаревшим кодом». Он помог мне пройти через ряд проектов на старых объектах, и такие вещи, как классы и методы, которых нельзя трогать, являются основными болевыми точками. Даже если вы этого не планировали, функция XYZ понадобится. Все о проверке будущего ...

Mark G 16.01.2009 20:18

@Mark G: наследование ограничивает изменения в реализации, поэтому я вообще не считаю, что это нужно для будущего. Это пределы будущих изменений, а не их разрешения.

Jon Skeet 16.01.2009 20:54

@Jon Skeet: По моему опыту, я просто не видел этого. Возьмите любой из диалогов в .NET BCL (Открыть / Сохранить / Печать), ничего страшного с ними сделать нельзя, потому что они запечатаны, и это большая проблема. Но это обсуждение, вероятно, должно быть в другом вопросе с тегом «Субъективный».

Mark G 16.01.2009 21:35

Еще два варианта:

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

  • поставить отметку в конструкторе для класса:

    if (this.getClass() != MyClass.class) {
        throw new RuntimeException("Subclasses not allowed");
    }
    

    Тогда никто не сможет создать подкласс вашего класса.

(Не то чтобы я предлагал использовать эти методы, это просто пришло мне в голову. Я бы использовал конечный класс и / или частный конструктор)

Крысы, я как раз собирался сам опубликовать исключение.

Michael Myers 16.01.2009 20:14

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

Tom Hawtin - tackline 16.01.2009 20:17

+1 Я не думал, что на этот вопрос будет реальный ответ, но я думаю, это так близко, как вы собираетесь получить.

Outlaw Programmer 16.01.2009 20:40

@Chris Lively: Конструктор из суперкласса должен вызываться всегда. Вы можете «переопределить» конструктор (хотя не существует такой вещи, как переопределяющий конструктор, поскольку конструктор не наследуется), но вы не можете «пропустить» конструктор из суперкласса.

Peter Štibraný 19.01.2009 11:23

Использование final - канонический способ.

public final class FinalClass {
  // Class definition
}

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

Причины, похожие на java.lang.String, я бы предположил.

duffymo 16.01.2009 20:38
  • Использовать окончательный
  • Используйте частные конструкторы
  • Используйте комментарий:

    // do not inherit
    
  • Используйте комментарий javadoc

  • Сделайте каждый метод окончательным, чтобы люди не могли их переопределить
  • Используйте проверку времени выполнения в конструкторе класса:

    if (this.getClass() != MyClass.class) {
        throw new RuntimeException("Subclasses not allowed");
    }
    

Идея комментария действительно не имеет особого смысла. Комментарий JavaDoc имеет гораздо больше смысла, но все же не надежен.

eleven81 16.01.2009 20:29

Сделайте ваши конструкторы частными и предоставьте фабричные функции для создания экземпляров.

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

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, так как это меньше кода и включает возможность создания объектов.

Другие вопросы по теме