неизменный класс должен быть окончательным?

Когда вы объявляете ссылочную переменную (т. е. объект), вы действительно создаете указатель на объект. Рассмотрим следующий код, в котором вы объявляете переменную примитивного типа int:

int x;
x = 10;

В этом примере переменная x является int, и Java инициализирует ее для 0. Когда вы назначаете его 10 во второй строке, ваше значение 10 записывается в ячейку памяти, на которую указывает x.

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

Integer num;
num = new Integer(10);

Первая строка объявляет переменную с именем num, но она не содержит примитивного значения. Вместо этого он содержит указатель (потому что тип Integer является ссылочным типом). Поскольку вы еще не указали, что указать на Java, он устанавливает значение null, что означает «Я ничего не указываю».

Во второй строке ключевое слово new используется для создания экземпляра (или создания ) объекту типа Integer и переменной указателя num присваивается этот объект. Теперь вы можете ссылаться на объект, используя оператор разыменования . (точка).

Exception, о котором вы просили, возникает, когда вы объявляете переменную, но не создавали объект. Если вы попытаетесь разыменовать num. Перед созданием объекта вы получите NullPointerException. В самых тривиальных случаях компилятор поймает проблему и сообщит вам, что «num не может быть инициализирован», но иногда вы пишете код, который непосредственно не создает объект.

Например, вы можете имеют следующий метод:

public void doSomething(SomeObject obj) {
   //do something to obj
}

В этом случае вы не создаете объект obj, скорее предполагая, что он был создан до вызова метода doSomething. К сожалению, этот метод можно вызвать следующим образом:

doSomething(null);

В этом случае obj имеет значение null. Если метод предназначен для того, чтобы что-то сделать для переданного объекта, целесообразно бросить NullPointerException, потому что это ошибка программиста, и программисту понадобится эта информация для целей отладки.

Альтернативно, там могут быть случаи, когда цель метода заключается не только в том, чтобы работать с переданным в объекте, и поэтому нулевой параметр может быть приемлемым. В этом случае вам нужно будет проверить нулевой параметр и вести себя по-другому. Вы также должны объяснить это в документации. Например, doSomething может быть записано как:

/**
  * @param obj An optional foo for ____. May be null, in which case 
  *  the result will be ____.
  */
public void doSomething(SomeObject obj) {
    if(obj != null) {
       //do something
    } else {
       //do something else
    }
}

Наконец, Как определить исключение & amp; причина использования Трассировки стека

20
задан mkobit 14 April 2016 в 16:19
поделиться

4 ответа

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

предположим Вам определили класс, чтобы быть неизменными, назвать это MyUrlClass, но Вы не отмечаете его финал.

Теперь, кто-то мог бы испытать желание написать код менеджера безопасности как это;

void checkUrl(MyUrlClass testurl) throws SecurityException {
    if (illegalDomains.contains(testurl.getDomain())) throw new SecurityException();
}

И вот то, что они вставили свой DoRequest (MyUrlClass url) метод:

securitymanager.checkUrl(urltoconnect);
Socket sckt = opensocket(urltoconnect);
sendrequest(sckt);
getresponse(sckt);

, Но они не могут сделать этого, потому что Вы не сделали финал MyUrlClass. Причина они не могут сделать этого, состоит в том, что, если они сделали, код мог бы избежать ограничений менеджера безопасности просто путем переопределения getDomain () для возврата "www.google.com" в первый раз, когда это называют, и "www.evilhackers.org" второе, и передача объекта их класса в DoRequest ().

у меня ничего нет против evilhackers.org, между прочим, если это даже существует...

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

я не думаю статья, на которую Вы сослались, должен быть взят в качестве инструкции, что "все неизменные классы должны быть окончательными", особенно, если у Вас есть положительная причина разработать Ваш неизменный класс для наследования. То, что это говорило, - то, что защита неизменности является допустимой причиной финала, где мнимые проблемы производительности (который является тем, о чем это действительно говорит в той точке) не допустимы. Обратите внимание, что это дало "сложный класс, не разработанный для наследования" как одинаково допустимая причина. Можно справедливо утверждать, что отказ составлять наследование в Ваших сложных классах является чем-то для предотвращения, как не удающийся составлять наследование в неизменных классах. Но если Вы не можете объяснить его, можно, по крайней мере, предупредить об этом факте путем предотвращения его.

6
ответ дан 30 November 2019 в 00:09
поделиться

Поскольку, если класс является окончательным, Вы не можете расширить его и сделать его изменяемым.

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

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

9
ответ дан 30 November 2019 в 00:09
поделиться

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

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

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

10
ответ дан 30 November 2019 в 00:09
поделиться

Это хорошая идея, чтобы сделать класс, неизменный по причинам производительности. Принять целое число. Например. Valueof. Когда вы называете этот статический метод, он не должен возвращать новый целочисленный экземпляр. Он может вернуть ранее созданный экземпляр безопасным в знании, что когда он передал вам ссылку на этот экземпляр в прошлый раз, когда вы его не изменяли (я думаю, это также хорошее рассуждение от перспективы причин безопасности).

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

Кроме того, вам не нужно сделать финал класса. Вы можете сделать конструкторы частным.

0
ответ дан 30 November 2019 в 00:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: