My question is very basic, but I would like to understand everything in 100%. Many questions in SO referes to my post, but I haven't find a satisfying answer.
We know that Enums in java are reference type. Let's consider the following snippet:
public static class A {
public int i;
public A(int i) {
this.i = i;
}
}
public static class Test {
int i;
A a;
public Test(int i, A a){
this.i = i;
this.a = a;
}
public Test(Test oldTest){
this.i = oldTest.i;
this.a = oldTest.a;
}
}
public static void main(String[] args) {
Test t1 = new Test(10, new A(100));
System.out.println(t1.i + " " + t1.a.i);
Test t2 = new Test(t1);
t2.i = 200;
t2.a.i = 3983;
System.out.println(t2.i + " " + t2.a.i);
System.out.println(t1.i + " " + t1.a.i);
}
Output is quite obvious because copy constructor of Test makes a shallow copy:
10 100
200 3983
10 3983
BUT because enums in java are also reference types I do not understand one thing. Let's replace A class by Enum:
public static enum TestEnum {
ONE, TWO, THREE;
}
public static class Test {
int i;
TestEnum enumValue;
public Test(int i, TestEnum enumVar){
this.i = i;
this.enumValue = enumVar;
}
public Test(Test oldTest){
this.i = oldTest.i;
this.enumValue = oldTest.enumValue; // WHY IT IS OK ??
}
}
public static void main(String[] args) {
Test t1 = new Test(10, TestEnum.ONE);
System.out.println(t1.i + " " + t1.enumValue);
Test t2 = new Test(t1);
t2.i = 200;
t2.enumValue = TestEnum.THREE; // why t1.emunValue != t2.enumValue ??
System.out.println(t2.i + " " + t2.enumValue);
System.out.println(t1.i + " " + t1.enumValue);
}
I was expecting output:
10 ONE
200 THREE
10 THREE <--- I thought that reference has been copied... not value
But I've got:
10 ONE
200 THREE
10 ONE
Question: Why? Where my thinking is incorrect?
There's nothing special about enums here. You'll see the exact same behaviour if you use strings or any type, basically.
Your two Test
objects are entirely separate. When you write:
t2.enumValue = TestEnum.THREE;
you're changing the value of the enumValue
field within the second object to be a reference to the object referred to by TestEnum.THREE
.
The two enumValue
fields (one via t1
and one via t2
) are entirely separate. Changing one field doesn't change another.
Now, if instead you made your enum mutable (which I would strongly discourage) and changed your code to something like this:
t2.enumValue.someMutableField = "a different value";
... then that would be visible via t1.enumValue
, because they both refer to the same object.
It's really important to differentiate between changing a field within an instance of Test
, and changing a field within an object that you happen to reach via an instance of Test
.
Again, this really isn't about enums. You may well find it's simpler to get your head round the idea by changing the enumValue
field to a String
field, and experimenting that way.