When using == for a primitive and a boxed value, is autoboxing done, or is unboxing done
It is defined in the JLS #15.21.1:
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).
And JLS #5.6.2:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:
- If any operand is of a reference type, it is subjected to unboxing conversion
So to answer your question, the
Integer is unboxed into an
In Java, does == Box or Unbox when comparing an object and a constant value?
What you call "a constant value" is an
int literal, so its type is
JLS 15.21.1 says:
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.
v1 == 1000 test,
1000 is of numeric type and
v1 is convertible to numeric type, so binary numeric promotion is performed.
JLS 5.6.2 (Binary numeric promotion) says:
If any operand is of a reference type, it is subjected to unboxing conversion
Integer operand -
v1 - is unboxed to an
int and a comparison of two
ints is performed. Therefore the result of the comparison is
When you compare two reference types -
v1 == v2 - no unboxing takes places, only the references are compared, as written in JLS 15.21.3:
If the operands of an equality operator are both of either reference type or the null type, then the operation is object equality.
1000 is too large to be cached by the
b2 are not referencing the same instance, and therefore the result of the comparison is
Java autoboxing and comparison of Objects using operators
<= are numerical comparison, and thus, the compiler knows it has to do unboxing.
!= always work as reference comparators for non-primitive types.
How does auto boxing/unboxing work in Java?
When in doubt, check the bytecode:
Integer n = 42;
0: bipush 42
2: invokestatic #16 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
So in actuality,
valueOf() is used as opposed to the constructor (and the same goes for the other wrapper classes). This is beneficial since it allows for caching, and doesn't force the creation of a new object on each boxing operation.
The reverse is the following:
int n = Integer.valueOf(42);
0: bipush 42
2: invokestatic #16 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: invokevirtual #22 // Method java/lang/Integer.intValue:()I
intValue() is used (again, it's analogous for the other wrapper types as well). This is really all auto(un)boxing boils down to.
You can read about boxing and unboxing conversions in JLS §5.1.7 and JLS §5.1.8, respectively.
Why do we use autoboxing and unboxing in Java?
Some context is required to fully understand the main reason behind this.
Primitives versus classes
Primitive variables in Java contain values (an integer, a double-precision floating point binary number, etc). Because these values may have different lengths, the variables containing them may also have different lengths (consider
On the other hand, class variables contain references to instances. References are typically implemented as pointers (or something very similar to pointers) in many languages. These things typically have the same size, regardless of the sizes of the instances they refer to (
This property of class variables makes the references they contain interchangeable (to an extent). This allows us to do what we call substitution: broadly speaking, to use an instance of a particular type as an instance of another, related type (use a
String as an
Object, for example).
Primitive variables aren't interchangeable in the same way, neither with each other, nor with
Object. The most obvious reason for this (but not the only reason) is their size difference. This makes primitive types inconvenient in this respect, but we still need them in the language (for reasons that mainly boil down to performance).
Generics and type erasure
Generic types are types with one or more type parameters (the exact number is called generic arity). For example, the generic type definition
List<T> has a type parameter
T, which can be
Object (producing a concrete type
List<Integer>) and so on.
Generic types are a lot more complicated than non-generic ones. When they were introduced to Java (after its initial release), in order to avoid making radical changes to the JVM and possibly breaking compatibility with older binaries, the creators of Java decided to implement generic types in the least invasive way: all concrete types of
List<T> are, in fact, compiled to (the binary equivalent of)
List<Object> (for other types, the bound may be something other than
Object, but you get the point). Generic arity and type parameter information are lost in this process, which is why we call it type erasure.
Putting the two together
Now the problem is the combination of the above realities: if
List<Object> in all cases, then
T must always be a type that can be directly assigned to
Object. Anything else can't be allowed. Since, as we said before,
double aren't interchangeable with
Object, there can't be a
List<double> (unless a significantly more complicated implementation of generics existed in the JVM).
But Java offers types like
Double which wrap these primitives in class instances, making them effectively substitutable as
Object, thus allowing generic types to indirectly work with the primitives as well (because you can have
List<Double> and so on).
The process of creating an
Integer from an
Float from a
float and so on, is called boxing. The reverse is called unboxing. Because having to box primitives every time you want to use them as
Object is inconvenient, there are cases where the language does this automatically - that's called autoboxing.
Why wrapped type unboxed instead of boxing the primitive?
Consider this scenario:
Boolean b1 = new Boolean(false); //I know you shouldn't be doing this but it's valid
boolean foo = b1 == false;
Boolean bar = b1 == false;
Now if things worked like you probably expect them to be,
foo would be true and
bar would be false. Or, alternatively both could be false but that would mean autoboxing everything all the time if just a single boxed primitive occurs in the expression. (And then potentially unboxing it for the assignment.)
I wouldn't consider that a good trade-off. Granted, dealing with NPEs from unboxing conversions is ugly but it's something you have to do anyway in most unboxing scenarios.
Java autoboxing rules
Unboxing will be happing when
comparison operators appear.
Integer a = 10;
a = a+10; //1.unboxing a to int 2.calculate a+10 3.boxing 20 to Integer.
System.out.print(a > 10); //1.unboxing a to int 2. compare
== appear, it depends.
If boxing type appear on
both side, it will compare
the reference.But if base type appear on
one side, and the other side is a boxing type, the boxing type will
unboxing to base type.
Integer a = new Integer(129);
Integer b = new Integer(129);
System.out.println(a == b); // compare reference return false
System.out.println(a == 129); // a will unboxing and compare 129 == 129 return true
Java.lang.Integer Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS.
See source code
Integer a = 127;
Integer b = 127; //cached, the same as b a==b return ture
Integer c = 129;
Integer d = 129; // not cached, c==d return false
Autoboxing Unboxing Operator (!=) and (==) difference
This is because 10 is in between the range [-128, 127]. For this range
== works fine since the JVM caches the values and the comparison will be made on the same object.
Every time an
Integer (object) is created with value in that range, the same object will be returned instead of creating the new object.
See the JLS for further information.
Why is autoboxing not allowed for primitive arrays when using Arrays.sort()?
According to the JLS, Section 5.1.7, there are only the following specified boxing conversions, and arrays aren't involved in any of them:
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
Why Does Java Code with an Inner Class Generates a Third Someclass$1.Class File
Hibernate/JPA - Annotating Bean Methods VS Fields
File Upload Using Selenium Webdriver and Java Robot Class
How to Add Close Button to a Jtabbedpane Tab
How to Create a Stream of Regex Matches
Java Inheritance - Calling Superclass Method
How to Invert the Case of a String in Java
Why Are Wait() and Notify() Declared in Java's Object Class
Java.Rmi.Connectexception: Connection Refused to Host: 127.0.1.1;
Reverse Hashmap Keys and Values in Java
How Does Double to Int Cast Work in Java
Tomcat 7 "Severe: a Child Container Failed During Start"
How to Test Abstract Class in Java with Junit
Understanding the etc/Gmt Time Zone
Modifier Static Is Only Allowed in Constant Variable Declarations