Array.equal() giving wrong output - java

To my understanding, the following code should print true, since both elements are equal.
From java docs Array.get() will return:
Returns the value of the indexed component in the specified array
object. The value is automatically wrapped in an object if it has a
primitive type.
However, when I run the following code it is printing
false:
public class Test1 {
static boolean equalTest(Object array1, Object array2) {
return Array.get(array1, 0).equals(Array.get(array2, 0));
}
public static void main(String[] args) {
int[] a = new int[1];
byte[] b = new byte[1];
a[0] = 3;
b[0] = 3;
System.out.println(equalTest(a, b));
}
}
My question is isn't classes implementing Number are or should be directly comparable to one another.

This has nothing to do with arrays really. Your comparison is equivalent to:
Object x = Integer.valueOf(3);
Object y = Byte.valueOf((byte) 3);
boolean equal = x.equals(y);
That's never going to return true.
Even though your original arrays are of the primitive types, Array.get returns Object, so you're getting the boxed types - and comparing values of those different types.

According to the documentation of Array.get(Object array,int index) method, the value returned is automatically wrapped in an object if it has a primitive type. So, if you add the following lines:
System.out.println(Array.get(array1, 0).getClass());
System.out.println(Array.get(array2, 0).getClass());
you will see the output is
class java.lang.Integer
class java.lang.Byte
The equals method of Integer class first of all checks if the object it is being compared to is also an instance of Integer, if not , then no further checks are required, they are not equal.
That's the reason you see the output is false as the objects being compared for equality are Integer and Byte.

The Array.get invocations return Integer and Byte object instances. These are not equal according to Integer.equals because the class type differs.

The problem is that the Array.get() method returns an object, so for int it'll return Integer, and for byte, it will return Byte. So .equals() method will return false because it first sees whether the type is the same, and then compares the values.

The array data types don't match. One is int and the other is byte. Since they're being passed to the function as Objects, they'll end up being Integer and Byte. So in order to compare them properly, you need to type-cast them to the same type. Something like:
static boolean equalTest(Object array1, Object array2) {
int int1 = (int) Array.get(array1, 0);
int int2 = (int) Array.get(array2, 0);
return int1.equals(int2);
// OR return int1 == int2;
}

If you look at the JavaDoc for Array.get you'll see:
The value is automatically wrapped in an object if it has a primitive
type.
So your bytes become Bytes and your ints become Integers.
That means the function you're calling is Integer.equals(Object)
This is implemented like so:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
You're not passing it an Integer, you're passing it a Byte so that's why it returns false.

Related

Integer object caching

I read that "So when creating an object using Integer.valueOf or directly assigning a value to an Integer within the range of -128 to 127 the same object will be returned."
This is the reason why :-
Integer a=100;
Integer b=100;
if(a==b) // return true as both the objects are equal
But why not in this below case?
These two values are also in the range of 127 and -128 so according to the statement above this two will also return the same objects.
But the output here i am getting as "Not"
public static void main(String[] args) {
Integer a = 10;
Integer b = 12;
if(a == b)
System.out.println("same");
else
System.out.println("Not");
}
Can someone explain?
You're misunderstanding what "the same object will be returned" means.
So, comparison with == is actually comparing memory locations, and returns true only when the two variables hold the same object (i.e. stored at the same memory location).
Values between -128 to 127 are stored in the integer constant pool, which means that every 10 is the same 10 (i.e. the same memory location), every 12 is the same 12, etc. But it's not the case that all 10s are also 12s, which is what your question is unintentionally assuming.
Anyway, once you get outside of that range, each primitive int is a new object and is assigned to a new memory location outside of the constant pool.
You can test that with the following code:
public static void main(String[] args) {
Integer a = 1000;
Integer b = 1000;
if(a == b)
System.out.println("same");
else
System.out.println("Not");
}
That will print "Not", because a and b are two different objects stored in different memory locations.
And this is why you should compare things with .equals()
==
Checks whether both the references are pointing to the same memory location.
In the first case both values are same so they are pointing to the same location only one object will be created.
Integer a=100;
Integer b=100;
if(a==b) // return true as both the objects are equal
In the second case both values are different so they have different memory location for each so two objects will be created.
public static void main(String[] args) {
Integer a = 10;
Integer b = 12;
if(a == b)
System.out.println("same");
else
System.out.println("Not");
}
If you read the actual Java doc, you'll see a clearer description of what it is actually doing
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
As the Integer returned must represent the specified int value, there is no possible way that
Integer a = 10;
Integer b = 12;
System.out.println((a==b));
will print "true", as clearly the same object couldn't represent both values.
Edit:
For the sake of precision - The Java standard doesn't require that Integer autoboxing (assigning a primitive int to an Integer object) uses Integer.valueOf(), so it is quite possible that in a conforming Java implementation
Integer a = 10;
Integer b = 10;
System.out.println((a==b));
will print "false";
Simply They are not same object, those are two different Integer instances for to hold the given value, so as if the object are different it will always print Not

Java operators -> how == operator works

Java operator == is used for reference comparison
then how can == be used for comparing int a =1; and int b = 1;
both values are stored in different locations then how it compares
As commented by Andy, the JLS states that the operator '==' is indeed used for reference type comparison but also for numeric type and Boolean type comparison.
int is a numeric type.
When comparing numeric types the values are compared (not the references).
However if you want to determine if the references of two integers are equal rather than the values then you can use the Integer class. This class simply wraps the primitive numeric type int.
Now consider the following code:
public class TestClass {
public static void main(String[] args)
{
Integer A = new Integer(1);
Integer B = new Integer(1);
Integer C = A;
if (A == B) System.out.println("Won't print."); // (1)
if (A.equals(B)) System.out.println("WILL Print!!!"); // (2)
if (A == C) System.out.println("WILL Print!!!"); // (3)
}
}
Because A and B are objects, the reference of A is compared to the reference of B. Even though their int values are the same, because they are independent references this statement is false.
The equals method compares the int values of each Integer object and thus is true.
Integer object C references object A. Hence this reference comparison will be true.

Java Compare 2 integers with equals or ==?

i am very very new to Java and i would like to know how can i compare 2 integers? I know == gets the job done.. but what about equals? Can this compare 2 integers? (when i say integers i mean "int" not "Integer").
My code is:
import java.lang.*;
import java.util.Scanner;
//i read 2 integers the first_int and second_int
//Code above
if(first_int.equals(second_int)){
//do smth
}
//Other Code
but for some reason this does not work.. i mean the Netbeans gives me an error: "int cannot be dereferenced" Why?
int is a primitive. You can use the wrapper Integer like
Integer first_int = 1;
Integer second_int = 1;
if(first_int.equals(second_int)){ // <-- Integer is a wrapper.
or you can compare by value (since it is a primitive type) like
int first_int = 1;
int second_int = 1;
if(first_int == second_int){ // <-- int is a primitive.
JLS-4.1. The Kinds of Types and Values says (in part)
There are two kinds of types in the Java programming language: primitive types (§4.2) and reference types (§4.3). There are, correspondingly, two kinds of data values that can be stored in variables, passed as arguments, returned by methods, and operated on: primitive values (§4.2) and reference values (§4.3).
If you want to compare between
1-two integer
If(5==5)
2- char
If('m'=='M')
3 string
String word="word"
word.equals("word")
int is primitive type.This itself having value but Integer is object and it is having primitive int type inside to hold the value.
You can do more operations like compare,longValue,..more by Using wrapper Integer.
== for Integer will not work the rang above -128 and 127. Integer hold cache value upto this range only in memory. More than this range you have to equals() method only to check Integer wrapper class.
equals() method will check the value stored in the reference location.
As int is primitive you can not use equals.
What you can do
Use Interger as wrapper
void IntEquals(Integer original, Integer reverse) {
Integer origianlNumber = original;
Integer reverseNumber = reverse;
if (origianlNumber.equals(reverse)) {
System.out.println("Equals ");
} else {
System.out.println("Not Equal");
}

Using Arraylist in Java

I have a problem using Arraylists in java my code looks something like this:
List<Integer> numbers1 = new ArrayList<>();
List<Integer> numbers2 = new ArrayList<>();
boolean bcompare;
I add to the lists the same numbers, but when i try to compare the numbers of the index 0 of the lists like this the result of the boolean is false when it should be true:
bcompare = numbers1.get(0)==numbers2.get(0);
bcompare is false
But here is the thing when I use some temp variables and then compare them it gives me what i expected, a true value on bcompare:
int a=numbers1.get(0);
int b=numbers2.get(0);
bcompare = a==b;
bcompare is true
What am I doing wrong here?
It is cause you use the wrapper classes Integer. So an == compares the "references".
Use the equals() method instead to compare values of objects:
bcompare = numbers1.get(0).equals(numbers2.get(0));
The second comparison is true, because a int is a primitive type and contains only the value.
Have a look at http://mindprod.com/jgloss/intvsinteger.html for more details about the difference between int and Integer
When compare the results of get, you are comparing Integers. Using ==, this will compare the two object references to see if they are the same reference. With the exception of Integer caching, this will be false.
When you first assign the numbers to int, Java unboxes the Integer to int, so that == can compare the primitive values directly. This works as you intended.
Use the last code which uses int values.
return type of get() method is Object so when you are comparing like this
bcompare = numbers1.get(0).equals(numbers2.get(0));
It compares the reference of two different object so giving false.
either use equals() method or downcast it to the Integer class.
Using equals() method is good idea out of these both.
As,others have already said bcompare = numbers1.get(0)==numbers2.get(0); compares references of 2 Integer objects (which are not same, so, it will be false). int a=numbers1.get(0); extracts the int value from Integers ( by calling integer.intValue() implicitly) and compares them so, a==b; will be true.
Byte code :
public static void main(java.lang.String[]);
*** some code here***
30: if_acmpne 37 // byte code instruction to compare references
49: invokevirtual #27 // Method java/lang/Integer.intValue:()I
*** some other code here **

Integer Enum and Unboxing

public class Document{
private Integer status;
// get()/set()
}
Then an enum:
public enum DocumentStatusEnum {
ACTIVE_DOCUMENT(2060),CANCELLED_DOCUMENT(2061),DRAFT_DOCUMENT(2062),PROCESSED_DOCUMENT(2063);
private final Integer value;
private DocumentStatusEnum(Integer value){
this.value = value;
}
public Integer getValue(){
return value;
}
}
In a method I'm using the above method as below:
Document d = new Document();
d.setStatus(2063);
if (d.getStatus() == DocumentStatusEnum.PROCESSED_DOCUMENT.getValue()){
{
// print true;
}
else{
// print false;
}
I get true here. Looks alright. In the same method, After couple of lines, I do this:
d.setStatus(2060)
if (d.getStatus() == DocumentStatusEnum.ACTIVE_DOCUMENT.getValue()){
// print true
}
else{
// print false
}
I get a false. I researched and found something about caching and boxing features in Java. I converted the enum definition as this:
public enum DocumentStatusEnum {
ACTIVE_DOCUMENT(2060),CANCELLED_DOCUMENT(2061),DRAFT_DOCUMENT(2062),PROCESSED_DOCUMENT(2063);
private final int value;
private DocumentStatusEnum(int value){
this.value = value;
}
public int getValue(){
return value;
}
}
Now, no issues. I get true in both cases.
Question is why this happening? I feel this behaviour is extremely unstable. It's a large application I'm dealing with and I'm using Integer == Integer comparison every where. Am I safe here?
Integer extends Object and therefore == is defined as reference equality, not value equality.
When comparing Integer with int, the Integer will be unboxed to an int, and the two operands will be compared for value equality. (Unless the Integer value is null, in which case NullPointerException will be thrown instead.) But Integer == Integer is never safe.
That said, because by default the runtime pre-allocates Integer instances for small integers (-128 through 127, according to the OpenJDK source), you can often get Integer == Integer to work for small values. But that behavior does not hold for larger values, and it is never required to hold. So you should never assume that two instances of Integer (or String, or any Object) will compare equal using ==, unless you are explicitly looking for reference equality.
You should use int instead of Integer, unless you need to handle null values.
There are indeed issues with comparing Integer objects. For example, the following will evaluate to false:
boolean test = (new Integer(1) == new Integer(1));
System.out.println(test); // "false"
These are just objects like any other. The == operator, when used with objects, only evaluates to true if they are the exact same Java object (as opposed to the equals() method, which can be overridden to compare the internals).

Categories