问题
Consider two references of type Integer that call the static factory method valueOf as shown below:-
Integer a = Integer.valueOf("10");
Integer b = Integer.valueOf("10");
Considering that Integer is immutable, is it ok to compare a and b using == instead of using equals method. I am guessing that the valueOf method makes sure that only one instance of Integer with the value 10 is created and a reference to this instance is returned for every Integer created with a value 10.
In general, is it ok to compare two references of an immutable class that are created using a call to the same static factory method by using == instead of equals?
Edit: The Integer class was used just as an example. I am aware thar Intgers upto 127 will return true if they are compared using ==. What i need to know is that when l create my own immutable class, say MyImmutable with a method create() that will ensure that no duplicate MyImmutable objects are created, will it be ok if I compare 2 MyImmutable references created using the create method by using == instead of equals.
回答1:
No, that's not safe in general. The ==
operator compares the references, not the values.
Using ==
happens to work for integers between -128 and 127, but not for other integers. The following code demonstrates that ==
won't always work:
Integer a = Integer.valueOf(10);
Integer b = Integer.valueOf(10);
System.out.println(a == b);
true
Integer c = Integer.valueOf(1000);
Integer d = Integer.valueOf(1000);
System.out.println(c == d);
false
See it working online: ideone
The explanation for this behaviour lies in the implementation of Integer.valueOf
:
public static Integer valueOf(int i) {
final int offset = 128;
if (i >= -128 && i <= 127) { // must cache
return IntegerCache.cache[i + offset];
}
return new Integer(i);
}
source
Not also that the standard requires that boxing integers for small inputs (-128 to 127) gives objects with equal references.
5.1.7 Boxing Conversion
If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.
However the standard makes no such guarantees for integers outside this range.
In general, is it ok to compare two references of an immutable class that are created using a call to the same static factory method by using == instead of equals?
As shown above, it won't work in general. But if you ensure that two immutable objects with the same value always have the same reference, then yes, it could work. However there are some rules you must follow carefully:
- The constructor must not be public.
- Every object you create via the static method must be cached.
- Every time you are asked to create an object you must first check the cache to see if you have already created an object with the same value.
回答2:
== and equals() is fundamentally different.
You should read this post for more details:
Difference between Equals/equals and == operator?
It has nothing to do with immutable objects.
回答3:
If your factory method returns the same object for equal inputs, it's safe to compare them with ==. For example String.intern works this way. Enums are also could be compared with ==. But Integer.valueOf returns the same object only for -128 ... 127 range (in default configuration).
Integer.valueOf(127) == Integer.valueOf(127)
but
Integer.valueOf(128) != Integer.valueOf(128)
Generally speaking you should use equals method to compare any objects. Operator == could be used to improve performance, when there are small number of different values for object. I wouldn't recommend to use this method, unless you are 100% sure in what you are doing.
回答4:
Immutability and equality do not necessarily have something to do with each other. == compares for reference equality, that means, it compares if both variables point to the very same instance of the object. Equality means that both objects share the same value. Immutability now means that you can not alter an object after its construction.
So, you might have two immutable obejcts, that represents the same value (meaning, they are equals so that a.equals(b) returns true) but that are not the same instance.
I have a little example for you here:
public class MyPoint { private int x; private int y; public MyPoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } @Override public boolean equals(Object obj) { if (!(obj instanceof MyPoint)) return false; MyPoint p = (MyPoint) obj; return this.x == p.x && this.y == p.y; } /** * @param args */ public static void main(String[] args) { MyPoint p = new MyPoint(2, 2); MyPoint q = new MyPoint(2, 2); MyPoint r = q; System.out.println(p == q); System.out.println(p == r); System.out.println(q == r); System.out.println(p.equals(q)); System.out.println(p.equals(r)); System.out.println(q.equals(r)); } }
The output is: false false true true true true
MyPoint is immutable. You can not change its values / its state after is has been initialized. But, as you can see, two objects of myPoint might be equal, but they might not be the same instance.
I think what you have in mind is some kind of flyweight pattern, where only one object exists for every possible state of the object. Flyweight also means commonly that those obejcts are immutable.
回答5:
They are not the same object, so ==
will not be true. With objects, be safe and use equals()
.
来源:https://stackoverflow.com/questions/10970823/is-it-ok-to-compare-immutable-objects-in-java-using-instead-of-equals