Encontrei o seguinte código em uma base de código em que estou trabalhando:
public final class ConfigurationService {
private static final ConfigurationService INSTANCE = new ConfigurationService();
private List providers;
private ConfigurationService() {
providers = new ArrayList();
}
public static void addProvider(ConfigurationProvider provider) {
INSTANCE.providers.add(provider);
}
...
INSTANCE
é declarado como final
. Por que os objetos podem ser adicionados INSTANCE
? Isso não deveria invalidar o uso de final. (Não faz).
Presumo que a resposta tenha a ver com ponteiros e memória, mas gostaria de saber com certeza.
Respostas:
final
simplesmente torna a referência do objeto imutável. O objeto para o qual ele aponta não é imutável ao fazer isso.INSTANCE
nunca pode se referir a outro objeto, mas o objeto ao qual se refere pode mudar de estado.fonte
ConfigurationService
objeto e tente fazer um INSTANCE =deserializedConfigurationService
não seria permitido?INSTANCE
para se referir a outro objeto. Não importa de onde veio o outro objeto. (NB, há umINSTANCE
porClassLoader
que carregou esta classe. Você poderia, em teoria, carregar a classe várias vezes em um JVM e cada um é separado. Mas este é um ponto técnico diferente.)Ser final não é o mesmo que ser imutável.
final != immutable
A
final
palavra-chave é usada para garantir que a referência não seja alterada (ou seja, a referência que ela possui não pode ser substituída por uma nova)Mas, se o atributo for self-modificável, não há problema em fazer o que você acabou de descrever.
Por exemplo
Se instanciarmos essa classe, não poderemos atribuir outro valor ao atributo
someFinalObject
porque ele é final .Portanto, isso não é possível:
Mas se o próprio objeto é mutável assim:
Então, o valor contido por aquele objeto mutável pode ser alterado.
Isso tem o mesmo efeito que sua postagem:
Aqui você não está alterando o valor de INSTANCE, você está modificando seu estado interno (por meio do método provider.add)
se você quiser evitar que a definição da classe seja alterada assim:
Mas, pode não fazer muito sentido :)
A propósito, você também precisa sincronizar o acesso a ele basicamente pelo mesmo motivo.
fonte
A chave para o mal-entendido está no título da sua pergunta. Não é o objeto que é final, é a variável . O valor da variável não pode mudar, mas os dados dentro dela podem.
Lembre-se sempre de que quando você declara uma variável de tipo de referência, o valor dessa variável é uma referência, não um objeto.
fonte
final significa apenas que a referência não pode ser alterada. Você não pode reatribuir INSTANCE a outra referência se ela for declarada como final. O estado interno do objeto ainda é mutável.
iria lançar um erro de compilação
fonte
Fonte
Aqui está um guia sobre como tornar um objeto imutável .
fonte
Final e imutável não são a mesma coisa. Final significa que a referência não pode ser reatribuída, então você não pode dizer
Imutável significa que o próprio objeto não pode ser modificado. Um exemplo disso é a
java.lang.String
classe. Você não pode modificar o valor de uma string.fonte
Java não possui o conceito de imutabilidade embutido na linguagem. Não há como marcar métodos como modificadores. Portanto, a linguagem não tem como impor a imutabilidade do objeto.
fonte