В основном безопасность, я думаю. По той же причине, по которой String является окончательным, все, что любой код, связанный с безопасностью, хочет рассматривать как неизменяемый, должен быть окончательным.
Предположим, у вас есть класс, определенный как неизменяемый, назовите его MyUrlClass, но вы не пометите его как final.
Теперь у кого-то может возникнуть соблазн написать такой код менеджера безопасности;
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 final. Причина, по которой они не могут этого сделать, заключается в том, что если бы они это сделали, код мог бы обойти ограничения менеджера безопасности, просто переопределив getDomain() так, чтобы он возвращал "www.google.com" при первом вызове, и "www.evilhackers.org" второй и передать объект своего класса в DoRequest().
Я ничего не имею против evilhackers.org, кстати, если он вообще существует...
При отсутствии проблем с безопасностью все дело в том, чтобы избежать ошибок программирования, и, конечно, от вас зависит, как вы это сделаете. Подклассы должны соблюдать контракт своего родителя, а неизменяемость — это только часть контракта. Но если предполагается, что экземпляры класса неизменны, то сделать его окончательным — это хороший способ убедиться, что все они действительно неизменны (т. класс называется).
Я не думаю, что статью, на которую вы ссылаетесь, следует воспринимать как инструкцию о том, что «все неизменяемые классы должны быть окончательными», особенно если у вас есть веская причина для разработки неизменяемого класса для наследования. Он говорил о том, что защита неизменяемости является веской причиной для final, когда воображаемые проблемы с производительностью (о чем он действительно говорит в тот момент) недействительны. Обратите внимание, что в качестве столь же уважительной причины указано «сложный класс, не предназначенный для наследования». Можно справедливо возразить, что неучета наследования в ваших сложных классах следует избегать, как и неучета наследования в ваших неизменяемых классах. Но если вы не можете объяснить это, вы можете, по крайней мере, сигнализировать об этом факте, предотвращая его.
person
Steve Jessop
schedule
28.09.2008