If instance variable is set final its value can not be changed like
public class Final {
private final int b;
Final(int b) {
this.b = b;
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.
When you declare a field
or reference
final, you must set the value once by the time the constructor exits.
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
.
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
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.
Edit 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.
In Short
normalMap= finalMap; //no error since normalMap is not final
finalMap =normalMap;// compiler error since normalMap is final
Note:- When you declare an object reference as final, it means that it will always point to the same object on heap to which it was initialized.
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?
1.) Java is pass by value so when you write cc.setConditionMap(cacheMap
) where cacheMap
is an object reference (Note:- cacheMap
is not an object itself, it is just a reference) then you are just passing the address of the object on heap to setConditionMap(cacheMap)
, now inside setConditionMap(cacheMap)
, conditionMap
is initialized with the value of cacheMap
(the value of cache Map is the address of Map Object). Now after this step both conditionMap
and cacheMap
refers to the same object on heap. But the catch is that you can again set the value of conditionMap
so that it points to some other map object on heap but cacheMap
will always point to the same Map Object.
2.) Declaring a variable as final doesn't means that object on heap is final(doesn't makes sense at all, right?) instead what it means is that it variable will always point to the object to which it was initialized and nobody can change it.
Let's say, final Map map = new HashMap(); new : is responsible to create object in heap which holds value
"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;
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();
}
}
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);
}
}
As the other answers have specified, you cannot make a final variable refer to another object.
Quoting from the Java Language Specification:
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.
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 refers to the same thing that CacheMap
is
referring to, and is not final itself.
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 never pass-by-reference - that's the reason why the "finalness" of CacheMap
wasn't getting passed around.
This question might help you: 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.
Your copy of the pointer isn't protected by final since you stored the copy to a non-final variable.