Primitive and Object comparison with == operator - java

I am wondering what is the internal Java behaviour for the next snippet:
Long a = 123L;
long b = 123;
System.out.println("a equals b?: " + (a == b));
The result is true although comparing two Long objects would be false (because it compares their reference). It is Java converting Long object into its primitive value because detects == operator against another primitive object?

It is Java converting Long object into its primitive value because detects == operator against another primitive object?
Yes. One of the operands is a primitive type and the other operand is convertible to a primitive by unboxing.
JLS section 15.21.1 says (emphasis mine):
If the operands of an equality operator are both of numeric type, or one is of numeric type and the other is convertible (§5.1.8) to numeric type, binary numeric promotion is performed on the operands (§5.6.2).
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).
Also, it is important to note that reference equality is only performed if both operands are objects. JLS section 15.21.3 says:
If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.

From the Java Tutorials:
Autoboxing and Unboxing
Autoboxing is the automatic conversion that the Java compiler makes
between the primitive types and their corresponding object wrapper
classes. For example, converting an int to an Integer, a double to a
Double, and so on. If the conversion goes the other way, this is
called unboxing.
Here is the simplest example of autoboxing:
Character ch = 'a';
The rest of the examples in this section use generics. If you are not
yet familiar with the syntax of generics, see the Generics (Updated)
lesson.
Consider the following code:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(i);
Although you add the int values as primitive types, rather than
Integer objects, to li, the code compiles. Because li is a list of
Integer objects, not a list of int values, you may wonder why the Java
compiler does not issue a compile-time error. The compiler does not
generate an error because it creates an Integer object from i and adds
the object to li. Thus, the compiler converts the previous code to the
following at runtime:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(Integer.valueOf(i));
Converting a primitive value (an int, for example) into an object of
the corresponding wrapper class (Integer) is called autoboxing. The
Java compiler applies autoboxing when a primitive value is:
Passed as a parameter to a method that expects an object of the
corresponding wrapper class.
Assigned to a variable of the
corresponding wrapper class.
Consider the following method:
public static int sumEven(List li) {
int sum = 0;
for (Integer i: li)
if (i % 2 == 0)
sum += i;
return sum;
}
Because the remainder (%) and unary plus (+=) operators do not apply
to Integer objects, you may wonder why the Java compiler compiles the
method without issuing any errors. The compiler does not generate an
error because it invokes the intValue method to convert an Integer to
an int at runtime:
public static int sumEven(List<Integer> li) {
int sum = 0;
for (Integer i : li)
if (i.intValue() % 2 == 0)
sum += i.intValue();
return sum;
}
Converting an object of a wrapper type (Integer) to its corresponding
primitive (int) value is called unboxing. The Java compiler applies
unboxing when an object of a wrapper class is:
Passed as a parameter to a method that expects a value of the corresponding primitive type.
Assigned to a variable of the corresponding primitive type.

Related

Comparing an int and Integer in Java

Consider the following snippet:
Integer Foo = 2;
int foo = 1;
boolean b = Foo < foo;
is < done using int or Integer? What about ==?
For all the relational operators (including therefore < and ==), if one type is the boxed analogue of the other, then the boxed type is converted to the unboxed form.
So your code is equivalent to Foo.intValue() < foo;. This is deeper than you might think: your Foo < foo will throw a NullPointerException if Foo is null.
According to JLS, 15.20.1
The type of each of the operands of a numerical comparison operator must be a
type that is convertible (§5.1.8) to a primitive numeric type, or a compile-time error occurs. Binary numeric promotion is performed on the operands (§5.6.2).
Further, 5.6.2 states that
If any operand is of a reference type, it is subjected to unboxing conversion
This explains what is happening in your program: the Integer object is unboxed before the comparison is performed.
They will be done using int due to Autoboxing and Unboxing.
The Wrapper types for primitive types in java does automatic "type casting" ( or autoboxing / unboxing) from Object to compatible primitive type. so Integer will be converted to int before passing it to comparison operators or arithmetic operators like < , > , == , = , + and - etc.

why is increment in reference of integer class object manipulates integer value?

I have a basic doubt, we can increment reference of Integer class object, while not reference of any other class(D class has 1 Integer data member and one parameterized constructor).
Integer x=new Integer(10); x++;
D d=new D(10); d++;
here both x and d are reference still we are able to increment Integer reference while not any other reference. I am missing something very basic, please help me out.
Integer x=new Integer(10); x++;
Here java compiler will do the un-boxing of the object, which converting the Integer object into primitive int. Then the increment operation will be performed. This is only defied for java primitives, the auto-boxing is converting primitive to wrapper object and reverse of it is call un-boxing. This is what is happening here.
The auto-boxing or un-boxing which is an automatic conversion, it is defined for java primitives only. So it can not be performed on other objects. Remember, the object are not just memory references like C or C++ that we can increment them.
This is because of Autoboxing for wrapper classes which was introduced from jdk 1.5. Internally java will convert the integer reference to int and increment it. You can't increment the objects.
Java has no way of overloading operators for arbitrary classes. Thus, D d; d++ is just not available. You can do:
public class D {
private int value;
public D( int v ){
value = v;
}
public void increment(){
value++;
}
}
Now you can do
D d = new D(10);
d.increment();
and d's value will be 11.
According to Oracle Java Documentation, The automatic conversion of primitive data types into its equivalent wrapper type is known as autoboxing and opposite operation is known as unboxing. Whenever we use object of wrapper class in an expression, automatic unboxing and autoboxing is done by JVM.
Integer object;
object = 100; //Autoboxing of int
++object;
When we perform an increment operation on Integer object, it is first unboxed, then incremented and then again reboxed into Integer type object. You can also take a look at How java auto boxing/unboxing works?

Integer vs. int comparison

I am new to java. I am now learning the non-primitive Integer type in java.
I know the following comparison is not valid and throws a compilation error -
String str = "c";
Char chr = 'c';
if(str == chr) return true;
The above code snippet gives me the - "Test.java:lineNumber: incomparable types: java.lang.String and char" errors.
But I found the following code snippet compiles fine -
int a = 1234;
Integer aI = 1234;
if(a==aI) return true;
Here, a is primitive int and aI is non-primitive. So how they are comparable? I am new to programming, may be is there any thing I don't know.
Thanks
The second snippet demonstrates an unboxing conversion. Boxing conversion allows a primitive type to be converted implicitly to a specific object wrapper type, e.g. int <-> Integer.
When comparing with the == operator, if one operand is a primitive type and the other is such a wrapper type, an unboxing conversion is performed so the 2 primitive values can be compared.
The first snippet doesn't compile because there is no boxing/unboxing relationship between String and char -- the relevant relationship is Character <-> char.
Section 5.1.8 of the JLS specifies all unboxing conversions:
From type Boolean to type boolean
From type Byte to type byte
From type Short to type short
From type Character to type char
From type Integer to type int
From type Long to type long
From type Float to type float
From type Double to type double
Section 5.1.7 specifies all boxing conversions, all of which are the reverse of the above.
This is called unboxing. Here aI is non-primitive/reference type. Here Integer is an wrapper of primitive int. Its gives some extra easy to use manipulations over primitive int. Each primitive type for example (boolean, byte, char, short, int, long, float, double) has a corresponding wrapper type (Boolean, Byte, Character, Short, Integer, Long, Float, Double).
So when a is compared with aI, first aI is unboxed and become a primitive int and it's value is compared with the primitive int. That means it is equivalent to -
int a = 1234;
Integer aI = 1234;
int a2 = aI.intValue();
if(a == a2) return true;
And for the first comparison the comparison occurred between completely two different data types - String and char. In this case there is no rule defined in java to convert char to String or String to char by default.
In first case the two data type are different. So they can not be compared.
And in second case, the two data type also different, but the wrapper Integer is made to support primitive int. So JVM automatically done the conversion of wrapper (unboxing) Integer to int and then compare. So actually in the second case two primitive int are compared to each other at the end.

Wrapper class as method return type

Can someone please explain how/why is this allowed in Java?
public class Test {
private int text;
public Integer getText() {
return text;
}
I am basically having the wrapper class as the return type, while I am infact returning a primitive.
Because Java supports Autoboxing and Unboxing in versions 5 and up. That is an example of the former, but the later is equally important (and the reverse conversion). Per the link,
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes.
Consider the following code: (From: http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html)
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(i);
Although you add the int values as primitive types, rather than Integer objects, to li, the code compiles. Because li is a list of Integer objects, not a list of int values, you may wonder why the Java compiler does not issue a compile-time error. The compiler does not generate an error because it creates an Integer object from i and adds the object to li. Thus, the compiler converts the previous code to the following at runtime:
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(Integer.valueOf(i));
Converting a primitive value (an int, for example) into an object of the corresponding wrapper class (Integer) is called autoboxing. The Java compiler applies autoboxing when a primitive value is:
Passed as a parameter to a method that expects an object of the corresponding wrapper class.
Assigned to a variable of the corresponding wrapper class.
From javadocs : Since java 5 Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on.
The java compiler applies autoboxing usually when -
Passed as a parameter to a method that expects an object of the
corresponding wrapper class.
Assigned to a variable of the corresponding wrapper class.
For the sake of performance, not everything in Java is an object. There are also primitives, such as int, long, float, double, etc.
For example java.lang.Integer class :-
It wraps an int.
Has two static final fields of type int: MIN_VALUE and MAX_VALUE.
MIN_VALUE contains the minimum possible value for an int (-2^31) and MAX_VALUE the maximum possible value for an int (2^31 - 1).
It also has two constructors - public Integer (int value) & public Integer (String value).
Integer has the no-arg byteValue, doubleValue, floatValue, intValue, longValue, and shortValue methods that convert the wrapped value to a byte, double, float, int, long, and short, respectively.
In addition, the toString method converts the value to a String.
Static methods parse a String to an int (parseInt) and convert an int to a String (toString).
class AutoBox {
public static void main(String args[]) {
// autobox an int
Integer a = 100;
// auto-unbox
int b = a;
System.out.println(b + " " + a); // displays 100 100
}
}
This feature has been added in Java 5.
text gets converted automatically into Integer by compiler. So basically its a syntactic sugar that can shorten your code (otherwise you would do conversions back and forth by yourself). Of course it has its price and if this happens a lot (I mean really a lot, big loops, frequent invocations and so forth), it can become a performance issue, so when using it, just remember the it happens under the hood and you'll be fine.
Integer.valueOf(text)
is called under the hood
The feature is called autoboxing btw
Hope this helps

Why can I pass a primitive to a method that takes an object?

Why is it possible to pass a primitive to a method that takes an object? Is the primitive turned into an object? like int = Integer and boolean = Boolean?
I can call the following function:
hash(41, 0);
public static int hash(int seed, Object object)
{
int result = seed;
if(object == null)
{
return hash(result, 0);
}
else if(!isArray(object))
{
result = hash(result, object.hashCode());
}
else
{
int length = Array.getLength(object);
for(int index = 0; index < length; ++index)
{
Object item = Array.get(object, index);
// prevent looping if item in array references the array itself
if(!(item == object))
{
result = hash(result, item);
}
}
}
return result;
}
Yes, this is called a boxing conversion. The int value is "boxed" into an Integer, which is an Object. It has been available in Java since 1.5.
The JLS, Section 5.1.7 lists available boxing conversions:
Boxing conversion converts expressions of primitive type to
corresponding expressions of reference type. Specifically, the
following nine conversions are called the boxing conversions:
From type boolean to type Boolean
From type byte to type Byte
From type short to type Short
From type char to type Character
From type int to type Integer
From type long to type Long
From type float to type Float
From type double to type Double
From the null type to the null type
Additionally, the boxing conversion is allowed during method invocation conversion, which is really what's going on here. The value is being converted to another type because the int 0 is being passed to a method that expects an Object. The JLS, Section 5.3, lists boxing conversion as one method of method invocation conversion:
Method invocation contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by widening reference
conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
Yes you can. Something called autoboxing/unboxing is done by the compiler automatically. Here is an excerpt from the docs.
Autoboxing is the automatic conversion that the Java compiler makes
between the primitive types and their corresponding object wrapper
classes. For example, converting an int to an Integer, a double to a
Double, and so on. If the conversion goes the other way, this is
called unboxing.
int i = 1;
Integer boxI = i; // Autoboxing is performed automatically by the compiler
Integer ii = 1;
int i = ii; // Auto(un)boxing is performed automatically by the compiler
Yes, primitive is converted to Object and vice versa, and this concept is called boxing and unboxing. In newer versions of java this is done automatically, hence called, auto-boxing and auto-unboxing.
Oracle doc for Boxing and UnBoxing
Each primitive has corresponding Wrapper class.
int -> Integer
boolean -> Boolean
char -> Character
and so on.

Categories