简体   繁体   English

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

[英]Why can final object be modified?

I came across the following code in a code base I am working on: 我在我正在处理的代码库中遇到以下代码:

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 is declared as final . INSTANCE宣布为final Why can objects be added to INSTANCE ? 为什么可以将对象添加到INSTANCE Shouldn't that invalidate the use of final. 不应该使final的使用无效。 (It doesn't). (它没有)。

I'm assuming the answer has to do something with pointers and memory but would like to know for sure. 我假设答案必须用指针和内存做一些事情,但我想肯定知道。

final simply makes the object reference unchangeable. final只是使对象引用不可更改。 The object it points to is not immutable by doing this. 它指向的对象不是一成不变的。 INSTANCE can never refer to another object, but the object it refers to may change state. INSTANCE永远不会引用另一个对象,但它引用的对象可能会改变状态。

Being final is not the same as being immutable. 最终与不可变是不一样的。

final != immutable

The final keyword is used to make sure the reference is not changed ( that is, the reference it has can't be substituted with a new one ) final关键字用于确保引用不会更改(即,它的引用不能替换为新引用)

But, if the attribute is self is modifiable it is ok to do what you have just described. 但是,如果属性是self是可修改的,那么你可以按照你刚才描述的那样做。

For instance 例如

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

If we instantiate this class, we won't be able to assign other value to the the attribute someFinalObject because it is final . 如果我们实例化这个类,我们将无法将其他值someFinalObject属性,因为它是final

So this is not possible: 所以这是不可能的:

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

But if the object it self is mutable like this: 但如果它自己的对象是可变的,就像这样:

class MutableObject {
     private int n = 0;

     public void incrementNumber() {
         n++;
     }
     public String toString(){
         return ""+n;
     }
}  

Then, the value contained by that mutable object may be changed. 然后,可以改变该可变对象包含的值。

SomeHighLevelClass someObject = new SomeHighLevelClass();

someObject.someFinal.incrementNumber();
someObject.someFinal.incrementNumber();
someObject.someFinal.incrementNumber();

System.out.println( someObject.someFinal ); // prints 3

This has the same effect that your post: 这与你的帖子有同样的效果:

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

Here you are not changing the value of INSTANCE, your are modifying its internal state ( via, providers.add method ) 这里你没有改变INSTANCE的值,你正在修改它的内部状态(via,providers.add方法)

if you want to prevent that the class definition should be changed like this: 如果你想防止类定义应该像这样改变:

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 :) 
....

But, it might not make much sense :) 但是,它可能没有多大意义:)

By the way, you also have to synchronize access to it basically for the same reason. 顺便说一句,您还必须基本上以同样的原因同步对它的访问

The key to the misunderstanding is in your question's title. 误解的关键在于你的问题标题。 It's not the object which is final, it's the variable . 它不是最终的对象 ,而是变量 The variable's value can't change, but the data within it can. 变量的值不能改变,但其中的数据可以改变。

Always remember that when you declare a reference type variable, the value of that variable is a reference, not an object. 始终记住,当您声明引用类型变量时,该变量的值是引用,而不是对象。

final just means the reference can't be changed. final只是意味着引用无法更改。 You can't reassign INSTANCE to another reference if it's declared as final. 如果将INSTANCE声明为final,则无法将其重新分配给另一个引用。 The internal state of the object is still mutable. 对象的内部状态仍然是可变的。

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

would throw a compilation error 会抛出编译错误

Once a final variable has been assigned, it always contains the same value. 一旦分配了final变量,它总是包含相同的值。 If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object. 如果final变量包含对对象的引用,则可以通过对对象的操作来更改对象的状态,但该变量将始终引用同一对象。 This applies also to arrays, because arrays are objects; 这也适用于数组,因为数组是对象; if a final variable holds a reference to an array, then the components of the array may be changed by operations on the array, but the variable will always refer to the same array. 如果final变量包含对数组的引用,则数组的组件可能会被数组上的操作更改,但变量将始终引用相同的数组。

Source 资源

Here's a guide on making an object immutable . 这是一个使对象不可变的指南。

Final and immutable are not the same thing. 最终和永恒不是一回事。 Final means the reference cannot be reassigned so you can't say 最终意味着参考不能重新分配,所以你不能说

INSTANCE = ...

Immutable means that the object itself cannot be modified. 不可变意味着对象本身不能被修改。 An example of this is the java.lang.String class. 一个例子是java.lang.String类。 You cannot modify the value of a string. 您无法修改字符串的值。

Java doesn't have the concept of immutability built into the language. Java没有内置于该语言中的不可变性概念。 There is no way to mark methods as a mutator. 没有办法将方法标记为mutator。 Therefore the language has no way to enforce object immutability. 因此,语言无法强制实现对象不变性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM