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

2022-08-31 10:36:08

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

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声明为 。为什么可以将对象添加到 ?这难道不应该使最终版的使用无效吗?(事实并非如此)。finalINSTANCE

我假设答案必须与指针和内存有关,但想确定。


答案 1

final只是使对象引用不可更改。它指向的对象不是通过执行此操作不可变的。 永远不能引用另一个对象,但它所引用的对象可能会改变状态。INSTANCE


答案 2

最终状态并不等同于不可变。

final != immutable

关键字用于确保引用未更改(即,它具有的引用不能替换为新引用)final

但是,如果属性是 self 是可修改的,则可以执行您刚才描述的操作。

例如

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

如果我们实例化此类,我们将无法为该属性分配其他值,因为它是最终值someFinalObject

所以这是不可能的:

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

这与您的帖子具有相同的效果:

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

在这里,您没有更改实例的值,而是修改其内部状态( via, providers.add method )

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

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

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

顺便说一句,出于同样的原因,您还必须同步对它的访问


推荐