如果实例变量设置为final,则其值不能像
那样更改public class Final {
private final int b;
Final(int b) {
this.b = b;
}
int getFinal() {
return b = 8; // COMPILE TIME ERROR
}
}
在代码的某处我看到实例类变量 HashMap 被声明为最终
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.
答案 0 :(得分:33)
您无法更改购物篮。你仍然可以改变里面的水果。
来自Language specification # chapter 14.12.4
一旦指定了最终变量,它总是包含相同的值。如果final变量保存对象的引用,则可以通过对象上的操作更改对象的状态,但变量将始终引用同一对象。
当您声明field
或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
分配一个final
声明map
。当您检索到正常情况时,只有{J} {}} {}} {}} {}} {}}}
简而言之
final
答案 1 :(得分:16)
final
与变量所引用的对象的内容无关。您将无法更改变量的值并使其引用另一个对象。
答案 2 :(得分:3)
我认为你在“最终”和“不可变”之间感到困惑 对象..
public class Final {
private final int b;
Final(int b) {
this.b = b;
}
int getFinal() {
return b = 8; // COMPILE TIME ERROR
}
}
最终意味着您无法更改对象的引用。如果是基元,则表示您无法更改该值。因此,当您尝试将b设置为8时,会出现编译时错误。
cc.setConditionMap(cacheMap);
public void setConditionMap(Map conditionMap) {
this.conditionMap = conditionMap;
}
在Java中 - “对象的引用按值传递”(正如Bruce Eckel在他的书“Thinking in Java”中所说的那样)。所以,您传递的是参考文献的副本。因此,您现在有2个对同一个cacheMap的引用。
因此,您可以使用任何引用更改cacheMap。但是你可以只重新分配另一个对象的“复制”引用,因为它不是最终的(不是原始的,原始的是最终的,不能指向另一个对象)。
答案 3 :(得分:2)
正如其他答案所指定的那样,你不能将引用的最终变量设为另一个对象。
引用Java Language Specification:
<强> 4.12.4。最终变量
最终变量只能分配给一次...如果最终变量包含对象的引用,则对象的状态可能会被对象上的操作更改,但变量将始终引用相同的对象
在您的问题的已编辑部分中,该规则未被违反:
您已将CacheMap
声明为最终版,并且您没有重新分配新内容
值任何地方。如果你能够做到这一点,那将是一个
违反。
cachemapdeclaredasfinal
只有引用与CacheMap
相同的内容
指的是不最终本身。
正如Suresh提到的upthread,如果您阅读Java中的值和引用,将会有所帮助。一个很好的起点是这个主题:Is Java "pass by reference"?。确保你理解为什么Java总是按值传递并且从不传递引用 - 这就是为什么CacheMap
的“最终性”没有被传递的原因。 / p>
答案 4 :(得分: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
}
答案 5 :(得分:0)
这个问题可能会对您有所帮助:http://www.stackoverflow.com/questions/40480/is-java-pass-by-reference
根据我的理解,这就是实际发生的事情: 当您使用java将对象传递给方法时,您基本上是将指针传递给该对象。因此,当你调用cc.geConditionMap()时,你基本上得到了指针。当你改变它时,你实际上并没有改变对象。您正在将指针的副本指向另一个地图。
由于您将副本存储到非最终变量,因此您的指针副本不受最终保护。
答案 6 :(得分:0)
以“C / C ++”术语:
Thing * a;
Thing * const b;
Thing const * c;
Thing const * const d;
Java中的“final”最接近“b”。 “b”是指向Thing的常量指针。 “b”不能改为指向不同的东西,但是事物本身可能会改变。
Java没有“c”和“d”的表示。 “c”是指向常数Thing的指针。 “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”很常见。
答案 7 :(得分:0)
这是我所知道的关键字final的用法:
在班级宣言中
这意味着该类:不能分类
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() {
//...
}
}
在收藏中&amp;图强>
这意味着集合无法重新初始化,但并不意味着元素是不可变的,每个元素都不会被关键字final
public class SomeClass {
final HashMap<K, V> someMap = new HashMap<K, V>();
}
答案 8 :(得分:0)
当引用为final时,它不能链接到任何其他对象。
可以更改对象的值,因此您可以向地图添加值,但不能更改地图的对象。
答案 9 :(得分:-1)
让我们说, final 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
import java.util.HashMap; import 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();
}
}
class 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);
}
}
答案 10 :(得分:-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并不意味着堆上的对象是最终的(根本没有意义,对吧?)而是意味着它变量总是指向它的对象已初始化,没有人可以改变它。