В основном безопасность, я думаю. По той же причине, по которой строка является окончательной, все, что любой код, связанный с безопасностью, хочет считать неизменным, должно быть окончательным.
Предположим, у вас есть класс, определенный как неизменяемый, назовите его MyUrlClass, но вы не помечаете его как окончательный.
Теперь у кого-то может возникнуть желание написать такой код менеджера безопасности;
void checkUrl(MyUrlClass testurl) throws SecurityException {
if (illegalDomains.contains(testurl.getDomain())) throw new SecurityException();
}
И вот что они поместили бы в метод DoRequest (URL-адрес MyUrlClass):
securitymanager.checkUrl(urltoconnect);
Socket sckt = opensocket(urltoconnect);
sendrequest(sckt);
getresponse(sckt);
Но они не могут этого сделать, потому что вы не сделали MyUrlClass финальным. Причина, по которой они не могут этого сделать, заключается в том, что если бы они это сделали, код мог бы избежать ограничений диспетчера безопасности, просто переопределив getDomain () для возврата «www.google.com» при первом вызове и «www.evilhackers.org». второе и передача объекта своего класса в DoRequest ().
Кстати, я ничего не имею против evilhackers.org, если он вообще существует ...
В отсутствие проблем безопасности все сводится к тому, чтобы избежать ошибок программирования, и, конечно, вам решать, как вы это сделаете. Подклассы должны соблюдать контракт своих родителей, а неизменность является лишь частью контракта. Но если предполагается, что экземпляры класса являются неизменяемыми, то сделать его окончательным - это хороший способ убедиться, что все они действительно неизменны (то есть, что не существует изменяемых экземпляров подклассов, которые можно использовать везде, где родитель класс называется).
Я не думаю, что статья, на которую вы ссылались, должна восприниматься как инструкция о том, что «все неизменяемые классы должны быть окончательными», особенно если у вас есть веская причина создать свой неизменяемый класс для наследования. Он говорил о том, что защита неизменности является веской причиной для окончательного решения, когда воображаемые проблемы с производительностью (о чем на самом деле идет речь в этот момент) недопустимы. Обратите внимание, что он дал «сложный класс, не предназначенный для наследования» в качестве одинаково веской причины. Можно справедливо утверждать, что отказ от учета наследования в ваших сложных классах - это то, чего следует избегать, так же, как отказ от учета наследования в ваших неизменяемых классах. Но если вы не можете объяснить это, вы можете, по крайней мере, сообщить об этом факте, предотвратив его.