Почему нужно использовать публичные конструкторы в логических и подобных неизменяемых классах? - PullRequest
5 голосов
/ 08 апреля 2010

(Для целей этого вопроса давайте предположим, что кто-то намеренно не использует auto (un) бокс), либо потому, что он пишет код перед Java 1.5, либо потому, что кто-то считает, что autounboxing слишком упрощает создание NullPointerException s.)

Взять, к примеру, Boolean. Документация для конструктора Boolean(boolean) гласит:

Примечание. Редко уместно использовать этот конструктор. Если только новый требуется экземпляр, статическая фабрика valueOf(boolean) обычно лучший выбор. Это может дать значительно лучшее пространство и время производительность.

У меня вопрос: зачем вам когда-либо хотеть получить новый экземпляр? Кажется, что все было бы проще, если бы такие конструкторы были частными. Например, если бы они были, вы могли бы написать это без опасности (даже если myBoolean были null):

if (myBoolean == Boolean.TRUE)

Было бы безопасно, потому что все true Booleans были бы ссылками на Boolean.TRUE, а все false Booleans были бы ссылками на Boolean.FALSE. Но поскольку конструкторы общедоступны, возможно, кто-то их использовал, а это значит, что вы должны написать это вместо:

if (Boolean.TRUE.equals(myBoolean))

Но на самом деле все становится плохо, когда вы хотите проверить два Booleans на равенство. Примерно так:

if (myBooleanA == myBooleanB)

... становится таким:

if (
    myBooleanA == myBooleanB ||
    (myBooleanA != null && myBooleanA.equals(myBooleanB))
)

ОБНОВЛЕНИЕ: С выпуском Java 7, java.util.Objects делает возможной эту более простую конструкцию:

if (Objects.equals(myBooleanA, myBooleanB))

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

Ответы [ 3 ]

5 голосов
/ 08 апреля 2010

Кэшированные значения никогда не собираются сборщиком мусора, поэтому используйте конструкторы всякий раз, когда вы хотите использовать их как мягкие / слабые ссылки, чтобы они могли быть собраны сборщиком мусора в любом случае, когда это необходимо. То же самое относится к Long#valueOf(), Integer#valueOf() и согласовывается со значениями в пределах кэшируемых диапазонов.

Выполнение поиска ссылок в Eclipse обнаруживает, что при каждом java.lang.Thread используется new Boolean() в качестве кеша на основе мягких ссылок, это даже явно комментируется (в методе isCCLOverridden()):

/*
 * Note: only new Boolean instances (i.e., not Boolean.TRUE or
 * Boolean.FALSE) must be used as cache values, otherwise cache
 * entry will pin associated class.
 */
1 голос
/ 08 апреля 2010

Конструкторы общедоступны из-за обратной совместимости ... .valueOf () был добавлен только в Java 1.4 ...

Также использование логического значения в качестве переменной с тремя состояниями в вашем примере (null / TRUE / FALSE), вероятно, является плохой идеей - лучше использовать enum (UNKNOWN, TRUE, FALSE) или, если null не является допустимым значение, проверьте его и вручную распакуйте для проверки равенства.

0 голосов
/ 08 апреля 2010

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

Это внесло недостаток дизайна, о котором вы говорите, и, следовательно, был введен автобокс.

EDIT

И конструкторы являются публичными, потому что они всегда были публичными. Перед миром автобокса в каком-то очень плохом коде вы хотели, чтобы new Integer(0) != new Integer(0) было правдой. Это был недостаток оригинального дизайна, однако, поскольку теперь он является частью открытого интерфейса, они не хотят ломать старый код.

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

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