14

インスタンス変数が final に設定されている場合、その値は次のように変更できません

public class Final {

    private final int b;

    Final(int b) {
        this.b = b; 
    }

    int getFinal() {
        return  b = 8;  // COMPILE TIME ERROR 
    }
}


コードのどこかで、インスタンス クラス変数 HashMap が final として宣言されているのを見ました

 private  final Map<String, Object> cacheMap = new HashMap<String, Object>();

なぜそう宣言されているのか理解できませんでしたか?通常、その場合は宣言されます。ハッシュマップを入れたら、その値を変更できなかったということですか?

編集:
final として宣言されている cacheMap がパラメーターとして別のクラスに渡された場合、参照を変更しても final のエラーは表示されません。なぜそうなのですか?

 class CacheDTO {

    private Map conditionMap;

    public Map getConditionMap() {
        return conditionMap;
    }

    public void setConditionMap(Map conditionMap) {
        this.conditionMap = conditionMap;
    }
}

それで

private  final Map<String, Object> cacheMap = new HashMap<String, Object>();
CacheDTO cc = new CacheDTO();
cc.setConditionMap(cacheMap);
Map<String, Object> cacheMapDeclaredAsFinal = cc.getConditionMap();
Map<String, Object> newMap = new HashMap<String, Object>();
cacheMapDeclaredAsFinal = newMap;    // In this case no error is shown. Though cacheMapDeclaredAsFinal reference is obtained by calling cc.getConditionMap() and cacheMapDeclaredAsFinal refers to final.
4

11 に答える 11

33

バスケットを変更することはできません。それでも、中の果物を変更できます。

言語仕様から# 14.12.4章

最終変数が割り当てられると、常に同じ値が含まれます。最終変数がオブジェクトへの参照を保持している場合、オブジェクトの状態はオブジェクトに対する操作によって変更される可能性がありますが、変数は常に同じオブジェクトを参照します。

fieldまたはfinalを宣言するreference ときは、コンストラクターが終了するまでに一度値を設定する必要があります。

コンストラクターでのみ、その変数に値を割り当てることができます。

 private  final Map<String,Object> CacheMap = new HashMap<String,Object>();

ここでできること

CacheMap.put(.....  

クラスで一緒に。

しかし、あなたはできません

CacheMap =   something.  //compile error.

と の違いを知っておく必要がvalueありreferenceます。

編集

ここ

 Map<String, Object> cachemapdeclaredasfinal = cc.geConditionMap();

 Map<String, Object> newMap = new HashMap<String, Object>();

 cachemapdeclaredasfinal  = newMap; // In this case no error is shown

理由 、

cachemapdeclaredasfinal 新しいマップではないので、別の参照 です conditionMap

このような新しいインスタンスを作成するとき

   Map<String, Object> cachemapdeclaredasfinal =
                                new HashMap<String, Object>(cc.geConditionMap());

そのエラーは消えます。newを使用したため。

編集2:

 private Map conditionMap;

 public void setConditionMap(Map ConditionMap) {
        this.conditionMap = conditionMap;
    }
  private  final Map<String, Object> CacheMap = new HashMap<String, Object>();
  CacheDto cc = new CacheDto();
  cc.setConditionMap(CacheMap);
  Map<String, Object> cachemapdeclaredasfinal = cc.geConditionMap();
  Map<String, Object> newMap = new HashMap<String, Object>();
 cachemapdeclaredasfinal  = newMap;

ここであなたが混乱したのはあなたです。

final宣言さmapれたものを normal(non final)に割り当てていmapます。その法線を取得すると、それを取得するだけで、それをさらにfinal使用することができますassign

要するに

normalMap= finalMap; //no error since normalMap is not final
finalMap =normalMap;// compiler error since normalMap is final
于 2013-09-27T11:34:32.850 に答える
16

final変数が参照しているオブジェクトの内容とは何の関係もありません。変数の値を変更して別のオブジェクトを参照させることはできません。

于 2013-09-27T11:32:51.257 に答える
3

「最終」オブジェクトと「不変」オブジェクトの間で混乱していると思います..

public class Final {

     private final int b;

     Final(int b) {
            this.b = b; 
     }

     int getFinal() {
          return  b = 8;  // COMPILE TIME ERROR 
     }
}

Final は、オブジェクトへの参照を変更できないことを意味します。プリミティブの場合、値を変更できないことを意味します。したがって、b を 8 に設定しようとすると、コンパイル時エラーが発生します。

cc.setConditionMap(cacheMap);

public void setConditionMap(Map conditionMap) {
        this.conditionMap = conditionMap;
}

Java の場合 - 「オブジェクトへの参照は値によって渡されます」(Bruce Eckel が著書「Thinking in Java」で述べているように)。したがって、参照のコピーを渡しています。したがって、現在、同じ cacheMap への参照が 2 つあります。

したがって、任意の参照を使用して cacheMap を変更できます。ただし、「コピーされた」参照のみを別のオブジェクトに再割り当てできます。これは最終的なものではないためです (元の参照ではなく、元の参照は最終的なものであり、別のオブジェクトを指すことはできません)。

于 2013-10-04T08:10:11.063 に答える
2

他の回答が指定しているように、最終変数に別のオブジェクトを参照させることはできません。

Java言語仕様からの引用:

4.12.4. 最終変数

final 変数は 1 回しか割り当てられない場合があります... final 変数がオブジェクトへの参照を保持している場合、オブジェクトの操作によってオブジェクトの状態が変更される可能性がありますが、変数は常に同じオブジェクトを参照します。

質問の編集部分では、そのルールに違反していません。

  • final として宣言しましたが、どこCacheMapにも新しい値を再割り当てしていません。そんなことができたら違反です。

  • cachemapdeclaredasfinal参照しているものと同じものをCacheMap参照するだけであり、最終的なものではありません。

Suresh が upthread について言及しているように、Java の値と参照について調べてみると役に立ちます。良い出発点は、このスレッドです: Is Java "pass by reference"? . Java が常に値渡しであり、決して参照渡しではない理由を理解していることを確認してください。これが、の「最終性」がCacheMap渡されなかった理由です。

于 2013-09-30T11:11:00.573 に答える
0

これは、hasmap を変更できないことを意味します。ハッシュマップ内の要素は、最後の区切り文字に関連付けられていません。

private static final HashMap<K, V> map = new HashMap<K, V>();

public void foo(K k, V v) {
    map.push(k, v);  //This is allowed
    map = new HashMap<K, V>  //This is not allowed
}
于 2013-09-27T11:36:32.550 に答える
0

参照が最終的なものである場合、他のオブジェクトにリンクすることはできません。

オブジェクトの値は変更できるため、マップに値を追加することはできますが、マップのオブジェクトを変更することはできません。

于 2014-08-19T09:53:00.987 に答える
-1

たとえば、最終的な Map map = new HashMap(); としましょう。new : 値を保持するヒープにオブジェクトを作成する責任があります

「マップ」参照は、最終的なスタックに作成されます。

The value of "map" reference is real object created in heap.
As "map" reference is final, it can not have any other value in it.

When we pass "map" reference, Actually we pass the value of map which is nothing but reference of object created in heap. In the called method, another
reference "map" will be created in stack which holds the same reference of object in heap.

The same concept is coded in this example

java.util.HashMap をインポートします。java.util.Map をインポートします。

public class FinalExample { public static void main(String[] args) {

    // Please see this example in case of normal variable and go through the
    // comment
    Final1 f1 = new Final1();
    f1.fun2();

    // Please see this example in case of Map Object and go through the
    // comment
    Final2 f2 = new Final2();
    f2.fun2();

}

}

クラス Final1 {最終的な int a = 10;

void fun1(int a) {
    a += 20;
    System.out.println(a);
}

void fun2() {

    // Here we are passing just content of final variable "a" but not the
    // block "a" itself.

    // When method fun1 is called another local block "a" will be created
    // This local "a" has nothing to do with instance final "a". Both are
    // different
    // We can change the value of local a it has nothing to do with instance
    // "a"

    fun1(a);
}

}

class Final2 { final static Map map = new HashMap();

static {
    map.put("1", "Nandeshwar");
    map.put("2", "Sah");
}

void fun1(Map map) {
    map.put("3", "John");
    map.put("4", "Nash");

    System.out.println(map);
}

void fun2() {

    // Here (in fun1) we pass the content of final map. The content of final
    // map is
    // the refernece of real object which holds the value
    // "1" "Nandeshwar // "2" "Sah".

    // When we call fun1, Another object "map(Map)" will be created. this
    // newly created object "map" will also
    // indicate the same reference as instance map refers

    // So the local object "map" and instance object "map" both is
    // different. But indicates the real Object which holds the value
    fun1(map);
}

}

于 2013-09-30T07:40:02.420 に答える