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 章

一旦分配了最终变量,它总是包含相同的值。如果最终变量持有对对象的引用,则对象的状态可能会通过对对象的操作而改变,但变量将始终引用同一个对象。

声明 afieldreference final 时,必须在构造函数退出时设置一次值。

您只能在构造函数中为该变量赋值。

 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”一书中所说的那样)。因此,您正在传递参考的副本。因此,您现在有 2 个对同一个 cacheMap 的引用。

因此,您可以使用任何引用更改 cacheMap。但是您只能将“复制的”引用重新分配给另一个对象,因为它不是最终的(不是原始的,原始的是最终的并且不能指向另一个对象)。

于 2013-10-04T08:10:11.063 回答
2

正如其他答案所指定的,您不能使最终变量引用另一个对象。

引用Java 语言规范

4.12.4。最终变量

一个final变量只能被赋值一次……如果一个final变量持有一个对象的引用,那么对象的状态可能会通过对对象的操作而改变,但变量总是引用同一个对象。

您的问题的编辑部分没有违反该规则:

  • 您已声明CacheMap为 final,并且您没有在任何地方重新为其分配新值。如果你能做到这一点,那就是违规了。

  • cachemapdeclaredasfinal指指所指的同一事物CacheMap,并且本身不是最终的。

正如 Suresh 提到的上行线程,如果您阅读 Java 中的值和引用会有所帮助。一个很好的起点是这个线程:Java“通过引用传递”吗?. 确保你理解为什么 Java 总是按值传递而不是按引用传递——这就是为什么“最终性”CacheMap没有被传递的原因。

于 2013-09-30T11:11:00.573 回答
0

这个问题可能会对您有所帮助:http: //www.stackoverflow.com/questions/40480/is-java-pass-by-reference

据我了解,这就是实际发生的情况:当您使用 java 将一个对象传递给一个方法时,您基本上是在传递一个指向该对象的指针。因此,当您调用 cc.geConditionMap() 时,您基本上是在获取指针。当你改变它时,你实际上并没有改变对象。您正在使指针的副本指向不同的地图。

您的指针副本不受最终保护,因为您将副本存储到非最终变量。

于 2013-09-30T04:46:37.990 回答
0

这是我知道的关键字 final 的用法:

在类声明中

这意味着 class: 不能被子分类

public final class SomeClass {
//...
}

在全局变量中

这意味着一旦为它分配了一个值,它就不能改变。

public class SomeClass  {
     private final int value = 5;
}

如果不赋值会出现编译错误,但你可以做的是使用组合来赋值。

public class SomeClass  {
     private final int value;
     public SomeClass(int value) {
       this.value=value
      }
}

在对象参数中

这意味着传递的对象不能更改

public class SomeClass {
   public void someMethod(final String value) {
      //...
   }
}

在局部变量中

这意味着该值一旦分配就不能改变

public class SomeClass {
   public void someMethod(final String value) {
      final double pi = 3.14;
   }
}

在方法中

这意味着该方法不能被覆盖

 public class SomeClass {
           public final void someMethod() {
              //...
           }
        }

在收藏和地图中

这意味着集合不能被重新初始化,但并不意味着元素是不可变的,每个元素都不会受到关键字的影响final

 public class SomeClass {
       final HashMap<K, V> someMap = new HashMap<K, V>();
  }
于 2013-10-06T19:20:20.907 回答
0

当引用是最终引用时,它不能链接到任何其他对象。

对象的值可以更改,因此您可以向地图添加值,但不能更改地图的对象。

于 2014-08-19T09:53:00.987 回答
0

在“C/C++”术语中:

Thing * a;
Thing * const b;
Thing const * c;
Thing const * const d;

Java 中的“final”最接近“b”。“b”是一个指向事物的常量指针。“b”不能更改为指向不同的事物,但事物本身可能会改变。

Java 没有“c”和“d”的表示。“c”是指向常量事物的指针。“c”可能指向其他事物,但它指向的事物不能改变(至少,不能通过“c”本身)

“d”结合了“b”和“c”:“d”是一个指向常量Thing的常量指针。

哦,“a”当然没什么特别的。

嗯...在 Java 中,并非所有事物都是对象,因此规则略有不同。

final int f = 9;

其中,在 C 中很像

int const f = 9;

这意味着您不能更改“f”或其整数值。

笔记:

int const f;
const int g;

两者的含义相同,但恕我直言,“f”具有更清晰的含义。不幸的是,“g”很常见。

于 2013-10-02T19:58:24.103 回答
0

这意味着不能更改hasmap。hashmap 中的元素与最终分隔符无关。

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 回答
-1

比方说,最终的 Map map = new HashMap(); new :负责在堆中创建具有价值的对象

“map”引用将在最终的堆栈中创建。

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;

公共类 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 { final 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 回答
-1

注意:- 当您将对象引用声明为 final 时,这意味着它将始终指向它被初始化的堆上的同一个对象。

如果将声明为 final 的 cacheMap 作为参数传递给另一个类,则如果我更改其引用,则不会为 final 显示错误。为什么会这样?

1.) Java 是按值传递的,所以当你写cc.setConditionMap(cacheMap)cacheMap对象引用在哪里(注意:-cacheMap不是对象本身,它只是一个引用)然后你只是将堆上对象的地址传递给setConditionMap(cacheMap),现在在里面setConditionMap(cacheMap),conditionMap用 的值初始化cacheMap(缓存 Map 的值是 Map Object 的地址)。现在在这一步之后,两者都conditionMap引用cacheMap了堆上的同一个对象。但要注意的是,您可以再次设置 的值conditionMap,使其指向堆上的其他映射对象,但cacheMap始终指向同一个映射对象。

2.) 将变量声明为 final 并不意味着堆上的对象是最终的(根本没有意义,对吗?)相反,这意味着它的变量将始终指向它被初始化的对象并且没有人可以改变它。

于 2017-07-29T15:14:25.380 回答