为什么 Java 中的最终实例类变量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19049697/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why final instance class variable in Java?
提问by abishkar bhattarai
If instance variable is set final its value can not be changed like
如果实例变量设置为 final,它的值不能像
public class Final {
private final int b;
Final(int b) {
this.b = b;
}
int getFinal() {
return b = 8; // COMPILE TIME ERROR
}
}
Somewhere in code I have seen instance class variable HashMapdeclared as final
在代码的某处,我看到实例类变量 HashMap声明为 final
private final Map<String, Object> cacheMap = new HashMap<String, Object>();
I could not understand why it is declared so? Normally in which case it is declared. Does it mean if once I put in hash map then I could not change its value?
我不明白为什么要这样声明?通常在这种情况下它被声明。这是否意味着一旦我放入哈希映射然后我就无法更改它的值?
Edit:
If cacheMap which is declared as final is passed as parameter to another class then error is not shown for final if I change its reference. Why it is so?
编辑:
如果声明为 final 的 cacheMap 作为参数传递给另一个类,那么如果我更改其引用,则最终不会显示错误。为什么会这样?
class CacheDTO {
private Map conditionMap;
public Map getConditionMap() {
return conditionMap;
}
public void setConditionMap(Map conditionMap) {
this.conditionMap = conditionMap;
}
}
Then
然后
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.
回答by Marko Topolnik
final
has nothing to do with the contents of the object the variable is referring to. You will only not be able to change the value of the variable and make it refer to another object.
final
与变量所指对象的内容无关。您将无法更改变量的值并使其引用另一个对象。
回答by Suresh Atta
You can't change the Basket. Still you can change the fruits inside.
你不能改变篮子。你仍然可以改变里面的水果。
From Language specification # chapter 14.12.4
Once a final variable has been assigned, it always contains the same value. If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.
一旦分配了最终变量,它始终包含相同的值。如果 final 变量持有对对象的引用,则对象的状态可能会因对对象的操作而改变,但变量将始终引用同一个对象。
When you declare a field
or reference
final, you must set the value once by the time the constructor exits.
当您声明 afield
或reference
final 时,您必须在构造函数退出时设置一次值。
You can assign a value to that variable only in constructor.
您只能在构造函数中为该变量赋值。
private final Map<String,Object> CacheMap = new HashMap<String,Object>();
here you can do
在这里你可以做
CacheMap.put(.....
with in the class.
在课堂上。
but you cannot do
但你不能做
CacheMap = something. //compile error.
You should know the difference between value
and reference
.
你应该知道的区别value
和reference
。
Edit
编辑
Here
这里
Map<String, Object> cachemapdeclaredasfinal = cc.geConditionMap();
Map<String, Object> newMap = new HashMap<String, Object>();
cachemapdeclaredasfinal = newMap; // In this case no error is shown
Reason ,
原因 ,
Since cachemapdeclaredasfinal
is not a new map it's another reference of conditionMap
由于 cachemapdeclaredasfinal
不是新地图,因此它是另一个参考 conditionMap
when you create a new instance like this
当您创建这样的新实例时
Map<String, Object> cachemapdeclaredasfinal =
new HashMap<String, Object>(cc.geConditionMap());
That error disappears. since you used new.
该错误消失了。因为你使用了new。
Edit 2 :
编辑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;
Here you what you confused is.
在这里,您感到困惑的是。
You are assigning one final
declared map
to some normal(non final
) map
. When you retrieved that normal only you are getting and that not final
so you can use/assign
it further.
您正在分配一个final
声明map
给一些 normal(non final
) map
。当你恢复正常时,只有你得到,而不是final
这样你可以assign
进一步使用/它。
In Short
简而言之
normalMap= finalMap; //no error since normalMap is not final
finalMap =normalMap;// compiler error since normalMap is final
回答by Micha?l Benjamin Saerens
It means that the hasmap cannot be changed. The elements inside the hashmap are not tied to the final delimiter.
这意味着无法更改 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
}
回答by Gennaro De Luca
This question might help you: http://www.stackoverflow.com/questions/40480/is-java-pass-by-reference
这个问题可能对你有帮助:http: //www.stackoverflow.com/questions/40480/is-java-pass-by-reference
From what I understand, this is what is actually happening: When you pass an object into a method with java, you're basically passing a pointer to the object. As such, when you call cc.geConditionMap(), you're basically getting the pointer back. When you change it, you're not actually changing the object. You are making your copy of the pointer point to a different map.
据我所知,这就是实际发生的事情:当您使用 java 将对象传递给方法时,您基本上是在传递指向该对象的指针。因此,当您调用 cc.geConditionMap() 时,您基本上是在取回指针。当你改变它时,你实际上并没有改变对象。您正在使指针的副本指向不同的地图。
Your copy of the pointer isn't protected by final since you stored the copy to a non-final variable.
您的指针副本不受 final 保护,因为您将副本存储到非 final 变量。
回答by Nandeshwar
Let's say, final Map map = new HashMap(); new : is responsible to create object in heap which holds value
比方说,final Map map = new HashMap(); new : 负责在堆中创建持有值的对象
"map" reference will be created in stack which is final.
“地图”引用将在最终的堆栈中创建。
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;
导入 java.util.HashMap; 导入 java.util.Map;
public class FinalExample { public static void main(String[] args) {
公共类 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;
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();
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);
}
}
}
回答by AbdullahC
As the other answers have specified, you cannot make a final variable referto another object.
正如其他答案所指定的那样,您不能使最终变量引用另一个对象。
Quoting from the Java Language Specification:
引用Java 语言规范:
4.12.4. final Variables
A final variable may only be assigned to once... If a final variable holds a reference to an object, then the state of the object may be changed by operations on the object, but the variable will always refer to the same object.
4.12.4. 最终变量
一个 final 变量只能被赋值一次...如果一个 final 变量持有一个对象的引用,那么对象的状态可能会因对对象的操作而改变,但该变量将始终指向同一个对象。
That rule isn't being violated in the edited portion of your question:
您的问题的编辑部分没有违反该规则:
You've declared
CacheMap
as final, and you're not reassigning a new value to it anywhere. If you'd be able to do that, it would be a violation.cachemapdeclaredasfinal
only refersto the same thing thatCacheMap
is referring to, and is notfinal itself.
您已声明
CacheMap
为 final,并且不会在任何地方为其重新分配新值。如果你能做到这一点,那就是违规了。cachemapdeclaredasfinal
仅指代所指的同一事物CacheMap
,而不是最终的本身。
As Suresh has mentioned upthread, it would help if you read up on values and references in Java. A good starting point is this thread: Is Java "pass by reference"?. Make sure you understand why Java is always pass-by-value and neverpass-by-reference - that's the reason why the "finalness" of CacheMap
wasn't getting passed around.
正如 Suresh 提到的 upthread,如果您阅读 Java 中的值和引用会有所帮助。这个线程是一个很好的起点:Java“通过引用传递”吗?. 确保你理解为什么 Java 总是按值传递而不是按引用传递——这就是为什么“最终性”CacheMap
没有被传递的原因。
回答by joeking
In "C/C++" terms:
在“C/C++”术语中:
Thing * a;
Thing * const b;
Thing const * c;
Thing const * const d;
The "final" in Java is closest to "b". "b" is a constant pointer to a Thing. "b" cannot be changed to point to a different Thing, but the Thing itself may be changed.
Java 中的“final”与“b”最接近。“b”是指向事物的常量指针。“b”不能改变为指向不同的事物,但事物本身可以改变。
Java doesn't have a representation for "c" and "d". "c" is a pointer to a constant Thing. "c" may point to other Things, but the Things it points to cannot be changed (at least, not through "c" itself)
Java 没有“c”和“d”的表示。“c”是一个指向常量 Thing 的指针。“c”可能指向其他事物,但它指向的事物不能改变(至少,不能通过“c”本身)
"d" combines "b" and "c": "d" is a constant pointer to a constant Thing.
"d" 结合了 "b" 和 "c":"d" 是一个指向常量 Thing 的常量指针。
Oh, and "a" of course is just nothing special.
哦,“a”当然没什么特别的。
Hm...In Java, not everything is an object so the rules are a little different.
嗯...在 Java 中,并非所有东西都是对象,因此规则略有不同。
final int f = 9;
Which, in C is much like
其中,在 C 中很像
int const f = 9;
Which means you cannot change "f" or its integer value.
这意味着您不能更改“f”或其整数值。
NOTE:
笔记:
int const f;
const int g;
both mean the same thing, but "f" IMHO has clearer meaning. "g" is unfortunately very common.
两者的意思相同,但“f”恕我直言,含义更明确。不幸的是,“g”很常见。
回答by TheLostMind
I think you are getting confused between "final" and "immutable" objects..
我认为您在“最终”和“不可变”对象之间感到困惑。
public class Final {
private final int b;
Final(int b) {
this.b = b;
}
int getFinal() {
return b = 8; // COMPILE TIME ERROR
}
}
Final means you cannot change the reference to the object. In case of primitives, it means you cannot change the value. So, when you try to set b to 8, you get a compile time error.
Final 意味着您不能更改对对象的引用。对于基元,这意味着您无法更改该值。因此,当您尝试将 b 设置为 8 时,您会收到编译时错误。
cc.setConditionMap(cacheMap);
public void setConditionMap(Map conditionMap) {
this.conditionMap = conditionMap;
}
In Java - "References to objects are passed by value" (As Bruce Eckel puts it in his book "Thinking in Java"). So, you are passing a copy of the reference. So, you have 2 references to the same cacheMap now.
在 Java 中 - “对对象的引用是按值传递的”(正如 Bruce Eckel 在他的书“Thinking in Java”中所说的那样)。因此,您正在传递引用的副本。因此,您现在有 2 个对同一个 cacheMap 的引用。
So, you can change the cacheMap using any of the references. But you can reassign only the "copied" reference to another object, as it is not final (not the original one, the original one is final and CANNOT point to another object).
因此,您可以使用任何引用更改 cacheMap。但是您只能将“复制的”引用重新分配给另一个对象,因为它不是最终的(不是原始的,原始的是最终的并且不能指向另一个对象)。
回答by sfrj
This are the usages of the keyword final that I know:
这是我知道的关键字 final 的用法:
In the class declaration
在类声明中
This means that the class: cannot be sub classed
这意味着 class: 不能被子类化
public final class SomeClass {
//...
}
In a global variable
在全局变量中
This means that once a value is assigned to it, it cannot change.
这意味着一旦为它分配了一个值,它就无法更改。
public class SomeClass {
private final int value = 5;
}
There will be a compile error if you don't assign the value, but what you can do is use composition to give a value.
如果不赋值会出现编译错误,但你可以做的是使用组合来赋值。
public class SomeClass {
private final int value;
public SomeClass(int value) {
this.value=value
}
}
In an object parameter
在对象参数中
This means that the passed object cannot be changed
这意味着无法更改传递的对象
public class SomeClass {
public void someMethod(final String value) {
//...
}
}
In local variables
在局部变量中
This means that the value cannot change once assigned
这意味着该值一旦分配就无法更改
public class SomeClass {
public void someMethod(final String value) {
final double pi = 3.14;
}
}
In methods
在方法中
This means that the method cannot be overriden
这意味着该方法不能被覆盖
public class SomeClass {
public final void someMethod() {
//...
}
}
In collections & maps
在收藏和地图中
This means that the collection cannot be reinitialized, but it doesn't mean that the elements are inmutable, each of the elements will not be afected by the keyword final
这意味着集合不能被重新初始化,但并不意味着元素是不可变的,每个元素都不会受到关键字的影响final
public class SomeClass {
final HashMap<K, V> someMap = new HashMap<K, V>();
}
回答by richa_v
When a reference is final, it cannot be linked to any other object.
当引用是最终的时,它不能链接到任何其他对象。
The values of the object can be changed, so you can add values to the map, but cannot change the object of the map.
对象的值可以更改,因此您可以向地图添加值,但不能更改地图的对象。