93

私が取り組んでいるコードベースで次のコードに出くわしました:

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ですか?それはfinalの使用を無効にするべきではありません。(そうではありません)。

答えはポインタとメモリで何かをしなければならないと思いますが、確かに知りたいです。

4

7 に答える 7

174

finalオブジェクト参照を変更できないようにするだけです。これを行うことにより、それが指すオブジェクトは不変ではありません。INSTANCE別のオブジェクトを参照することはできませんが、参照するオブジェクトの状態が変わる可能性があります。

于 2010-03-12T19:19:33.780 に答える
35

最終的であることは、不変であることと同じではありません。

final != immutable

キーワードは、参照が変更されていないことを確認するために使用されますfinal(つまり、参照を新しいものに置き換えることはできません)。

ただし、属性が self である場合は、今説明したことを実行しても問題ありません。

例えば

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

このクラスをインスタンス化すると、finalsomeFinalObjectであるため、属性に他の値を割り当てることができなくなります。

したがって、これは不可能です。

....
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);
}

ここでは、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 :) 
....

しかし、それはあまり意味がないかもしれません:)

ちなみに、基本的に同じ理由で、アクセスも同期する必要があります。

于 2010-03-12T19:38:04.770 に答える
27

誤解の鍵は、質問のタイトルにあります。最終的なのはオブジェクトではなく、変数です。変数の値は変更できませんが、変数内のデータは変更できます。

参照型変数を宣言する場合、その変数の値はオブジェクトではなく参照であることを常に覚えておいてください。

于 2010-03-12T19:22:08.647 に答える
13

finalは、参照を変更できないことを意味します。final として宣言されている場合、INSTANCE を別の参照に再割り当てすることはできません。オブジェクトの内部状態は変更可能です。

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

コンパイルエラーをスローします

于 2010-03-12T19:24:20.787 に答える
7

final変数が割り当てられると、常に同じ値が含まれます。変数がオブジェクトへの参照を保持している場合、finalオブジェクトの操作によってオブジェクトの状態が変更される可能性がありますが、変数は常に同じオブジェクトを参照します。配列はオブジェクトであるため、これは配列にも当てはまります。変数が配列への参照を保持している場合、final配列のコンポーネントは配列に対する操作によって変更される可能性がありますが、変数は常に同じ配列を参照します。

ソース

オブジェクトを不変にするためのガイドを次に示します。

于 2010-03-12T19:26:41.690 に答える
5

最終と不変は同じものではありません。Finalは、参照を再割り当てできないため、言うことができないことを意味します

INSTANCE = ...

不変とは、オブジェクト自体を変更できないことを意味します。この例はjava.lang.Stringクラスです。文字列の値を変更することはできません。

于 2010-03-12T19:20:33.687 に答える
2

Javaには、言語に組み込まれた不変性の概念がありません。メソッドをミューテーターとしてマークする方法はありません。したがって、言語にはオブジェクトの不変性を強制する方法がありません。

于 2010-03-12T19:51:09.170 に答える