Заключительные классы на Java, которые не должны быть финальными или наоборот?

Мне недавно задали этот вопрос в интервью:

Можете ли вы назвать какой-либо окончательный класс в Java API, которого не должно быть, или тот, которого нет и который должен быть?

Я не мог ни о чем думать. Вопрос подразумевает, что я должен знать все классы API как свои пять пальцев, чего я лично не ожидал бы от любого Java-разработчика.

Если кто-нибудь знает такие классы, приведите примеры.


person sotn    schedule 04.02.2013    source источник
comment
Вероятно, тест посвящен вашему опыту работы с Java API, это не значит, что вы должны знать его наизусть.   -  person Bogdan    schedule 04.02.2013
comment
В некоторых случаях, в основном при отладке ужасного кода, я бы посоветовал сделать Object окончательным.   -  person Kevin Bowersox    schedule 04.02.2013
comment
Вы не дали понять, какой вопрос хотите задать. Вы ищете пример, мнение по вопросу интервью, или что-то еще?   -  person Alvin Wong    schedule 04.02.2013
comment
что вы ответили участнику дискуссии?   -  person DDK    schedule 04.02.2013
comment
@DDK, мой ответ был очень похож на Anony-Moussse, за исключением того, что я не мог придумать класс BitSet.   -  person sotn    schedule 04.02.2013
comment
@Quoi, ты даже не представляешь, как ты ошибаешься. AtomicInteger, AtomicLong НЕ ДОЛЖНЫ быть окончательными. Фреймворк коллекций, являющийся окончательным, был бы за гранью ужасной идеи, а такие вещи, как JDO, не были бы реализованы.   -  person bestsss    schedule 06.02.2013


Ответы (7)


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

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

public class BrokenBigDecimal extends BigDecimal {
    public BigDecimal add(BigDecimal augend) {
        return BigDecimal.ZERO;
    }
}    

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

Перефразируя эффективную Java:

  • Оформить и оформить на наследство или запретить его
  • Классы должны быть неизменными, если нет веской причины сделать их изменяемыми.
person assylias    schedule 04.02.2013
comment
Вы можете создать неработающий список / коллекцию / и т. Д., BigDecimal, BigInteger в порядке, не являются окончательным imo. Вы можете отслеживать их, если хотите. Окончательность в их случае не поможет. - person bestsss; 06.02.2013

java.awt.Dimension не является окончательным и неизменным, и должно было быть. Все, что возвращает Dimension (например, объект Window), должно создавать защитные копии, чтобы не дать вызывающим абонентам делать неприятные вещи.

person Michael Barker    schedule 04.02.2013
comment
Это не является неизменным из-за того, что в старые времена создание новых объектов (и последующий сборщик мусора) было не совсем дешевым, как и Point / Rectangle. Эти классы должны быть одинаковыми по типу значений, но на данный момент в Java такое положение отсутствует. - person bestsss; 06.02.2013
comment
К сожалению, это была неверная оптимизация. Оставление его изменяемым означало необходимость создания защитных копий, которые оставляют не меньше увеличенного выделения / мусора. - person Michael Barker; 06.02.2013
comment
Как так? вы передаете размер как параметр, это была идея. Также копии необходимы только для кода клиентского пространства, внутри awt к объекту обращаются его поля (без копий). Я не защищаю оставить общедоступные области измерения, хотя ... просто объясняю - сделать это окончательным само по себе не помогло бы. - person bestsss; 06.02.2013
comment
Взгляните на метод size() на java.awt.Component, он копирует объект Dimension при каждом вызове. Вы правы, что сделать его окончательным - это необходимое, но не достаточное условие неизменности. - person Michael Barker; 07.02.2013
comment
size(), сам по себе, устарел, поэтому я полагаю, вы имели в виду getSize(). Посмотрите на правильный метод: Dimension size(Dimension rv) - вот что я имею в виду. Это была философия дизайна - передать объект для заполнения, если вы передадите null, вы получите совершенно новый объект. - person bestsss; 07.02.2013

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

Есть веские причины сделать Integer, Double и String всеми final.

Есть веские причины жаловаться на это.

Затем есть BitSet, BitInteger и т.д., которые можно было бы сделать final.

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

Чтобы выбрать конкретный класс: BitSet. Это не final, но вы не можете расширить его, добавив немного shift операции. С таким же успехом они могли сделать это final или позволить нам добавить такую ​​функциональность.

person Has QUIT--Anony-Mousse    schedule 04.02.2013
comment
Я не думаю, что это только вопрос вкуса - многие функции безопасности языка программирования Java зависят, например, от неизменности объектов String. А если вам нужна изменчивость, у вас есть изменяемый класс-компаньон StringBuilder. - person assylias; 04.02.2013

Выскакивает класс Date. Это изменяемый класс простых значений (по сути, оболочка для long), но хорошая эвристика состоит в том, что классы простых значений должны быть неизменяемыми. Также обратите внимание на многочисленные устаревшие методы: больше доказательств того, что дизайн был испорчен. Изменчивость Date является источником ошибок, требующих дисциплинированного защитного копирования.

person Raedwald    schedule 06.02.2013
comment
Класс данных подразделяется на java.sql.Date/Time/Timestamp, окончательный вариант не поможет, поскольку в нем есть методы установки. На самом деле быть не финальным - это хорошо, так как вы можете переопределить установщики и выбросить UnsupportedOperationException, сделав класс неизменным. - person bestsss; 06.02.2013
comment
@bestsss, поскольку у него есть методы установки: суть в том, что Date не должен иметь методов установки. - person Raedwald; 07.02.2013
comment
вопрос заключается в том, чтобы быть окончательным, а не в том, чтобы быть неизменным само по себе. Когда Date был впервые представлен, календаря не было, и сделать его неизменяемым позже было невозможно. Поэтому, если вам нужна неизменяемая дата, просто создайте ее - т.е. сделайте ее окончательной и запретите сеттеры. - person bestsss; 07.02.2013

тот, которого нет и должен быть

Большинство финальных классов в java спроектированы таким образом, что, учитывая соображения безопасности, в целом финальных классов относительно немного. Например, java.util.String является окончательным именно по этой причине. Как и многие другие. Некоторые классы с частным c-tor объявлены окончательными (Math, StrictMath), но в таком случае это не имеет значения.

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

Вкратце: я не могу придумать окончательный класс, которого не должно быть, однако есть некоторые, которые потенциально могли бы быть. Например, java.lang.Thread быть окончательным, возможно, не потребовалось для защиты от вредоносных clone().

person Community    schedule 06.02.2013

Я считаю, что java.util.Arrays и java.util.Collections должны быть объявлены окончательными.

Вот почему:

  1. Они содержат только статические члены и частный конструктор.
  2. Частный конструктор предотвращает расширение этих классов.

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

Кроме того, java.lang.Math (другой так называемый служебный класс) имеет такую ​​же структуру и также объявлен final.

person Marco    schedule 21.11.2018

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

Проверьте документы.

http://docs.oracle.com/javase/7/docs/api/java/lang/String.html

person Serdar Dogruyol    schedule 04.02.2013
comment
Почему он должен быть не окончательным? - person Has QUIT--Anony-Mousse; 04.02.2013
comment
Итак, String .NET также final и неизменяемый, как в Java. - person Alvin Wong; 04.02.2013
comment
Из любопытства; Что бы вы объяснили, чтобы сказать, что оно не должно быть окончательным? Поскольку вы говорите, что это очевидно. ;) - person class stacker; 04.02.2013
comment
Я не говорил, что это не должно быть окончательным. - person Serdar Dogruyol; 04.02.2013
comment
Эээ, да, да (или почему вы предложили это в качестве примера?) - person Graham Borland; 04.02.2013
comment
Вопрос был в том, можете ли вы назвать какой-либо окончательный класс в Java API, которого не должно быть, или тот, которого нет и должен быть? - person Subhrajyoti Majumder; 04.02.2013
comment
@SerdarDogruyol, возможно, вы захотите перечитать вопросы. Речь идет о классах, где final используется не очень хорошо. - person Has QUIT--Anony-Mousse; 04.02.2013