为什么可以修改最终对象?

我在我正在处理的代码库中遇到以下代码:

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被声明为final。 为什么可以将对象添加到INSTANCE中? 不应该使最终的使用无效。 (它不)。

我假设答案必须做指针和内存的东西,但想知道肯定。

“最终”只是使对象引用不可改变。 它指向的对象不是一成不变的。 INSTANCE永远不能引用另一个对象,但它引用的对象可能会改变状态。

作为最后的决定不是一成不变的。

final != immutable

final关键字用来确保引用没有被改变(也就是说,它的引用不能被新的引用所替代)

但是,如果这个属性是可修改的,那么就可以做你刚才描述的内容。

例如

 class SomeHighLevelClass { public final MutableObject someFinalObject = new MutableObject(); } 

如果我们实例化这个类,我们将无法为someFinalObject属性someFinalObject因为它是final的

所以这是不可能的:

 .... SomeHighLevelClass someObject = new SomeHighLevelClass(); MutableObject impostor = new MutableObject(); someObject.someFinal = impostor; // not allowed because someFinal is .. well final 

但是,如果它自己的对象是这样的可变的:

 class MutableObject { private int n = 0; public void incrementNumber() { n++; } public String toString(){ return ""+n; } } 

然后,该可变对象所包含的值可能会改变。

 SomeHighLevelClass someObject = new SomeHighLevelClass(); someObject.someFinal.incrementNumber(); someObject.someFinal.incrementNumber(); someObject.someFinal.incrementNumber(); System.out.println( someObject.someFinal ); // prints 3 

这和你的post有相同的效果:

 public static void addProvider(ConfigurationProvider provider) { INSTANCE.providers.add(provider); } 

这里你没有改变INSTANCE的值,你正在修改它的内部状态(通过providers.add方法)

如果你想防止类定义应该像这样改变:

 public final class ConfigurationService { private static final ConfigurationService INSTANCE = new ConfigurationService(); private List providers; private ConfigurationService() { providers = new ArrayList(); } // Avoid modifications //public static void addProvider(ConfigurationProvider provider) { // INSTANCE.providers.add(provider); //} // No mutators allowed anymore :) .... 

但是,这可能没有多大意义:)

顺便说一句,你也必须基于同样的原因同步访问它 。

误解的关键在于你的问题的标题。 这不是最终的对象 ,而是variables 。 variables的值不能改变,但其中的数据可以。

一定要记住,当你声明一个引用typesvariables时,该variables的值是一个引用,而不是一个对象。

最后只是意味着参考不能改变。 如果声明为final,则不能将INSTANCE重新分配给另一个引用。 对象的内部状态仍然是可变的。

 final ConfigurationService INSTANCE = new ConfigurationService(); ConfigurationService anotherInstance = new ConfigurationService(); INSTANCE = anotherInstance; 

会抛出一个编译错误

一旦分配了finalvariables,它总是包含相同的值。 如果finalvariables持有一个对象的引用,那么该对象的状态可以通过对该对象的操作来改变,但是该variables将总是引用相同的对象。 这也适用于数组,因为数组是对象; 如果finalvariables持有对数组的引用,那么数组中的组件可能会被数组上的操作所改变,但是variables将始终引用相同的数组。

资源

这是一个使对象不可变的指南。

最终和不可改变是不一样的。 最后意味着参考不能被重新分配,所以你不能说

 INSTANCE = ... 

不可变意味着对象本身不能被修改。 这个例子是java.lang.String类。 您不能修改string的值。

Java没有内置于语言中的不变性概念。 没有办法将方法标记为增变。 因此,语言没有办法强制对象不变性。

如果你正在使用final关键字对象,hashCode将永远不会改变,因此使它不可变。 它将以单例模式使用。

 class mysingleton1{ private mysingleton1(){} public static final mysingleton1 instance= new mysingleton1(); public static mysingleton1 getInstance(){ return instance; } }