Java Map Value Equality [duplicate] - java

This question already has answers here:
Comparing Integer objects vs int
(5 answers)
Closed 6 years ago.
While writing a graph algorithm, I saw that this -
Definition:
Map<Integer, Integer> componentNames = new HashMap<Integer, Integer>();
CASE I:
if (componentNames.get(A) == componentNames.get(B)) {
System.out.printn("Hi");
}
Does not print anything.
CASE II:
int componentNameA = componentNames.get(A);
int componentNameB = componentNames.get(B);
if (componentNameA == componentNameB) {
System.out.printn("Hi");
}
Prints "Hi"
I have printed to check the values. And, they were indeed same.
This is the first time I have seen strange behavior for Java.
What could be the reason for this?

CASE I:
if (componentNames.get(A) == componentNames.get(B)) {
System.out.printn("Hi");
}
The code doesn't enter the if condition because you are trying to compare two Integer references using == which will only return true if the LHS and RHS refer to the same object. In your case, it is safe to assume that componentNames.get(A) and componentNames.get(B) both return a reference to a separate Integer object.
It would be helpful to know that the JVM caches the values for wrapper classes and it is quite possible that the above if condition may be true if the JVM has cached the int value returned by componentNames.get(A) and componentNames.get(B). The JVM used to cache Integer values ranging between -128 to 127 but modern JVMs can cache values greater than this range as well.
int componentNameA = componentNames.get(A);
int componentNameB = componentNames.get(B);
if (componentNameA == componentNameB) {
System.out.printn("Hi");
}
The code enters condition because you are unboxing an Integer into an int and the comparison is done between two primitive values.
In general, two references when compared using == will only return true if both the references point to the same object. Therefore, it is advisable to compare two references using equals if you are checking for equality and compare them using == if you are looking to check for identity.

CASE 1:
componentNames.get(A) and componentNames.get(B) are references / pointers of two different instances of Integer Class.
So, componentNames.get(A) == componentNames.get(B) is false.
CASE 2:
int componentNameA and int componentNameB are int type variables.
As they both contain same value, componentNameA == componentNameB is true.

Related

How to compare int arrays in Java? [duplicate]

This question already has answers here:
Comparing integer Arrays in Java. Why does not == work?
(3 answers)
Closed 6 years ago.
When I am trying to compare two int array, even though they are exactly the same, the code inside if (one == two) still doesn't get executed. Why is this?
Object[] one = {1,2,3,4,5,6,7,8,9};
Object[] two = {1,2,3,4,5,6,7,8,9};
if (one == two){
System.out.println("equal");
} else {
System.out.println("not equal");
}
A few things to note here:
== compares the references, not the values . . . that is, you are asking whether these two arrays are the same exact instance, not whether they contain the same values.
The fact that you are using == means you may not know about the equals() method on Object. This is not the method you'll need to solve this current problem, but just be aware that in general, when you compare the values of two objects, you should be using obj1.equals(obj2), not obj1 == obj2. Now == does work with primitives like int (e.g. plain old x == 3 and so on), so maybe that's why you were using it, but I just wanted to make sure you were aware of equals() vs. ==.
In the old old days (pre-1998), you would have to compare each element pair of the two arrays. Nowadays, you can just use that static Arrays.equals() method on the java.util.Arrays class. This method is overloaded for all the primitive types (using == under the hood for each element pair) and for Object (where it will most definitely use equals() for each pair.)
The == operator does a reference equality check on objects (which arrays are). If the array elements are primitive (like int), you can use java.util.Arrays.equals. If they are themselves Objects, java.util.Arrays.deepEquals will do a deep equality test (provided the Objects in the array supply a suitable override of Object#equals.
You can do something like that:
public boolean compareArrays(int[] a, int[] b) {
boolean check = true;
if (a!= null && b!= null){
if (a.length != b.length){
check= false;
}else
for (int i = 0; i < b.length; i++) {
if (b[i] != a[i]) {
check= false;
}
}
}else{
check= false;
}
return check;
}
Or you could do something like that:
boolean areEqual = Arrays.equals(Arrays.sort(arr1), Arrays.sort(arr2));
You are comparing references. Compare the content instead with: Arrays.equals(one, two)
If you do this:
if (one == two){
then yo are comparing the references of the 2 arrays and not their content and that is wrong..
do instead
Arrays.equals(one, two)
== operator compares references and not actual values of everything that extends Object in java. This approach works on primitives only.

why Comparator<Integer[]> throws exception? [duplicate]

This question already has answers here:
Java: Integer equals vs. ==
(7 answers)
Closed 7 years ago.
I got an exception
java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(TimSort.java:868)
at java.util.TimSort.mergeAt(TimSort.java:485)
at java.util.TimSort.mergeCollapse(TimSort.java:408)
at java.util.TimSort.sort(TimSort.java:214)
at java.util.TimSort.sort(TimSort.java:173)
at java.util.Arrays.sort(Arrays.java:659)
at Main.main(Main.java:64)
when using this code :
Arrays.sort(arr, new Comparator<Integer[]>(){ //arr is 2D array
public int compare(Integer[] o1, Integer[] o2){
return o1[2]==o2[2]?0:o1[2]>o2[2]?1:-1;
}
});
which I believe is related to not satisfying transitivity of comparison, but when I made a little change like this :
Arrays.sort(arr, new Comparator<Integer[]>(){ //arr is 2D array
public int compare(Integer[] o1, Integer[] o2){
return o1[2].compareTo(o2[2]); // here is the change
}
});
the exception is no longer generated.
I can't understand an explanation of this issue as I'm sure that the Integer instance can be compared using relational operators (>, <, =) besides compareTo() method
Integer x = 1;
Integer y = 2;
System.out.println(x<y);
prints true as expected
can any body clarify ?
The problem is with:
o1[2]==o2[2]
This is comparing the Integers for identity. Equal instances are not necessarily identical. For example:
Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a == b); // False, instances are not identical.
System.out.println(a.equals(b)); // True, instances are equal.
It should be:
o1[2].equals(o2[2])
Or, to handle o1[2] being null:
Objects.equal(o1[2], o2[2])
since you are using Integer and not int, this is not valid:
o1[2]==o2[2]?0:o1[2]>o2[2]?1:-1;
you need to use equals or compareTo, not ==
The array you are sorting is made up of Integer objects. These are different than just plain old integers.
A plain old integer is just a number sitting in memory.
An Integer object is a an instance of a class that fills the same role as a basic integer, but also has a bunch of methods and data associated with it. That's the difference between being a piece of data or being an object.
The == operator compares numbers in memory. In the case of an instance of an object, it will compare the locations in memory, not the values of the numbers as you intend.
For Integer (and other number-like) objects, you must use the compareTo() method instead.
Your solution here is to either use the compareTo() method as suggested, or change your array to plain old integers.
You could also leave it as Integer objects and then use the Integer.intValue() to get a plain old integer returned, and then you can use the == comparison. But that's quite convoluted, IMO.

Why isn't Integer.MIN_VALUE equal to stored Integer.MIN_VALUE in variable?

I made an Interval class with the following fields:
...
private static final Integer MINF = Integer.MIN_VALUE;
Integer head,tail;
...
when I make an instance of this class, making this.head = Integer.MIN_VALUE, and I want to check if the value of head is equal to MINF, it says that they aren't equal.
Interval i = new Interval(Integer.MIN_VALUE,10);
System.out.println(i.toString()); //[-2147483648,10]
So I went ahead and tried to print the values,
public String toString() {
...
//What the hell?
System.out.println("MINF == Integer.MIN_VALUE: " + (MINF == Integer.MIN_VALUE)); //true
System.out.println("MINF == this.head: " + (MINF == this.head)); //false
System.out.println("Integer.MIN_VALUE == this.head: " + (Integer.MIN_VALUE == this.head)); //true
...
return "*insert interval in format*";
}
Which says
MINF == Integer.MIN_VALUE is true
MINF == this.head is false, although this.head = -2147483648
Integer.MIN_VALUE == this.head is true
Am I missing something for why the second one is false?
Integer is the wrapping class, child of Object and containing an int value.
If you use only the primitive type int, == does a numerical comparison and not an object address comparison.
Mind that Integer.MIN_VALUE of course is an int too.
You are missing the fact that when stored in Integer (that is, you store Integer.MIN_VALUE in two different integers) and using == between them, the comparison is not of the values, but of the objects.
The objects are not identical because they are two different objects.
When each object is compared to Integer.MIN_VALUE, since Integer.MIN_VALUE is an int, the object is autounboxed and compared using int comparison.
No one here has addressed the REASON why they're different objects. Obviously:
System.out.println(new Integer(10) == new Integer(10));
outputs false, for reasons that have been discussed to death in the other answers to this question and in Comparing Integer objects
But, why is that happening here? You don't appear to be calling new Integer. The reason is that:
Integer.MIN_VALUE returns an int, not an Integer.
You have defined MINF to be an Integer
Autoboxing uses valueOf. See Does autoboxing call valueOf()?
valueOf calls new Integer if the int is not in the integer cache,
The cache is only the values -128 -> 127 inclusive.
And that is why you are seeing the "two Integer objects are not == behavior", because of autoboxing. Autoboxing is also why equality does not appear to be transitive here.
You can fix this problem by instead using:
private static final int MINF = Integer.MIN_VALUE;
And, in general: don't use Integer for simple fields.; only use it as a generic type where you actually need the object.
You are using Integer objects. The use of == should be used as a comparison of individual primitive's values only. Since you used the Integer class rather than the primitive int then it is comparing the object's references between the two variables rather than their values.
Because MINF is a separate object to head you are receiving false for a direct comparison using ==.

How to compare Integer correctly in Java [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Integer wrapper class and == operator - where is behavior specified?
I known Java integer use cache in -127~128.
If
Integer i = 1;
Integer j = 1;
Integer m = 128;
Integer n = 128;
i == j // true
m == n // false
But I met a strange phenomenon.First,look at following snippet.
List<CustomerNotice> customerNotice = findByExample(example); // use Hibernate findByExample method
for(CustomerNotice n : customerNotice){
if(n.getConfirmStatus() == NoticeConfirmStatus.UNCONFIRMED.getValue()){
// do sth
}
}
public enum NoticeConfirmStatus{
UNCONFIRMED(1), //
CONFIRMED(2), //
FAILED_TO_CONFIRM(3); //
private final Integer value;
private NoticeConfirmStatus(Integer value) {
this.value = value;
}
public Integer getValue() {
return this.value;
}
}
public class CustomerNotice {
#Column(name = "CONFIRM_STATUS")
private Integer confirmStatus;
public Integer getConfirmStatus() {
return this.confirmStatus;
}
public void setConfirmStatus(Integer confirmStatus) {
this.confirmStatus = confirmStatus;
}
}
Although the if expression is not recommended, I think it will be return true,because n.getConfirmStatus()==1, but the result is false.I'm very confusing.
In addition, theList<CustomerNotice> customerNotice acquired by Hibernate findByExample method. Is there some Autoboxing or new operation when retrieve the resultset?
Thank you.
SHORT: (answers question)
If you want to compare Integers as the objects, you should use .equals:
i.equals(j);
m.equals(n);
With this, they should both return true. But if you really want to use ==, you need to get the primitive int value:
i.intValue() == j.intValue();
m.intValue() == j.intValue();
LONG: (explains answer)
The basis of this is that Objects are always stored separately in memory (except for some special cases like m=n), and to be compared properly, they need to be broken down into primitive types that can be compared successfully using ==.
Every Object has a .equals() method, which is inherited from Object as its superclass. However, it must be overridden to do a proper comparison. Integer overrides this method to compare to Integer objects successfully, while using == checks to see if both objects point to the same space in memory, and because two instances of an Object cannot point to the same space in memory, this will always return false.
However, as your code points out, there are some special cases that work, like these:
Your code uses a Integer i = 1, which is considered a "standard instance" and is able to be compared using ==.
If you set one Object equal to another using =, Java tells both objects to point to the same location in memory, which means that == will return true.
There are many others, but those are the two that come to mind and seem relevant.
You'll drive yourself crazy and waste a lot of time trying to figure out specific cases where this works or does not work. It depends on the implementation of code which isn't always visible to you.
The bottom line: never, ever, use == to compare Integer instances, period. As you have seen, it works sometimes, under some circumstances, and fails miserably the rest of the time. If you have a method that returns an Integer, then assign the value to an int, and then you can use == to compare that int to another int.

How is the == operator implemented in Java?

Specifically, in the case of object reference equality, what does the == operator do?
Does the comparison return true if the references evaluate to the same object address at the time of comparison? Or does it utilize the hashCode value of the two references to determine if the objects are the same?
To be very specific here, I would like to know what data structures managed by the JVM are referenced by the == operation for reference comparison. Does == rely on the OOP to perform reference comparison?
Unfortunately for me, the JLS does not define how the == operator must work. The Java API docs do not mention what == is supposed to do (they're for classes, right?)
PS: I was a bit intrigued by this question on hashcode uniqueness, and would prefer to know how the Sun JVM (or OpenJDK) implements the == operator.
The == operator just compares the references.
References in the JVM are just a standard object pointer. This works out to a single 32bit or 64bit integer value (depending on platform).
When you compare two object references, you're really just comparing two 32bit or 64bit integers, and if they're the same, you'll equate to equal. The integer values are a location in memory.
Because a reference is just a number, a reference comparison comes down to just comparing two numbers. No hash is needed.
The == operator compares object references to see if they are identical, i.e. they refer to the same object in memory.
The equals() method compares object references to see if they are equivalent, though not necessarily identical. The default implementation of equals() uses the == operator, but it often makes sense to override this behavior. For example, you might want two BankAccount references to be considered equivalent if they have the same account number, even if they are completely different objects.
The == operator returns true if the objects are the same object. There is not access to hashCode() or equals() here.
Try this to confirm:
public class Test {
static void testEqualEqual(Integer I0, Integer I1, boolean IsEquals) {
if(!(IsEquals == (I0 == I1)))
throw new AssertionError();
}
static void testEqual(Integer I0, Integer I1, boolean IsEquals) {
if(!(IsEquals == (I0.equals(I1))))
throw new AssertionError();
}
static void testHash(Integer I0, Integer I1, boolean IsEquals) {
if(!(IsEquals == (I0.hashCode() == I1.hashCode())))
throw new AssertionError();
}
public static void main(String ... args) {
testEqualEqual( 1, 1, true);
testEqualEqual(2000, 2000, false);
testEqual( 1, 1, true);
testEqual(2000, 2000, true);
testHash( 1, 1, true);
testHash(2000, 2000, true);
System.out.println("Done");
}
}
To understand this, you should know first that the number number 255 will be cached when autoboxed. This means that Integer of 1 is always the same object but Integer of 2000 will always be different object.
This experiment shows that '==' return true when the objects are the same. In case of '1' they are the same number and it returns true. But in case of '2000' autoboxed to be different objects so it returns false.
The experiment also shows that '==' does not use equals() or hashCode().
Hope this helps.

Categories