为什么可以修改最终对象?
我在我正在处理的代码库中遇到以下代码:
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;
会抛出一个编译错误
一旦分配了
final
variables,它总是包含相同的值。 如果final
variables持有一个对象的引用,那么该对象的状态可以通过对该对象的操作来改变,但是该variables将总是引用相同的对象。 这也适用于数组,因为数组是对象; 如果final
variables持有对数组的引用,那么数组中的组件可能会被数组上的操作所改变,但是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; } }