On Java -
Autoboxing
Starting from Java 5, we have a new feature called Autoboxing. It is known as several names: auto-boxing, boxing, and unboxing. Boxing and unboxing make wrapper classes more convenient.
Before Java 5, if we want to make a wrapper, unwrap it, use it, and then rewrap it, we might do something like this:
Integer iwrap = new Integer(345); // make it int junwrap = iwrap.intValue(); // unwrap it junwrap++; // use it iwrap = new Integer(junwrap); // rewrap it System.out.println("iwrap = " + iwrap); // print it
But in Java 5, we write the code:
Integer iwrap2 = new Integer(345); // make it iwrap2++; // unwrap it, increment it, and rewrap it System.out.println("iwrap2 = " + iwrap2); // print it
The output produced from the two versions is same:
iwrap = 346 iwrap2 = 346
The line of code:
Integer iwrap2 = new Integer(345); iwrap2++;
appears to be using post-increment operator on an object reference variable, iwrap2. However, the compiler does the unboxing and reassignment for us behind the scene. Though it also looks contradictory to the rule that wrapper objects are mutable because iwrap2's value changed from 345 to 346. What actually happened was that the second wrapper object was created and its value was set to 346.
Let's check it with the following example.
Integer iwrap3 = 345; Integer iwrap4 = iwrap3; System.out.println(iwrap3 == iwrap4); iwrap3++; System.out.println(iwrap3 + " " + iwrap4); System.out.println(iwrap3 == iwrap4);
Its output should look like this:
true 346 345 false
So, behind the scene, when the compiler got to the line
iwrap3++;
it had to substitute some like this:
int temp = iwrap3.intValue(); temp++; iwrap3 = new Integer(temp);
As we expected, there was a call to new.
We're going to look at how wrappers work with ==, !=, and equals() more thoroughly.
What would be the intention of using equals() method? Its main intention is to determine whether two instances of a given class are meaningfully equivalent. It's up to the designer of the class to decide what equivalent means for objects of the class in question. The API developers decided that for all the wrapper classes, tow objects are equal if they are of the same type and have the same value.So, it shouldn't be surprising that
Integer ia = 2010; Integer ib = 2010; if(ia != ib) System.out.println("They are not the same objects."); if(ia.equals(ib)) System.out.println("They are meaningfully equal.");produces the output like this:
They are not the same objects. They are meaningfully equal.
It's just two wrapper objects that happen to have the same value. Because they have the same int value, the equals() method think them to be meaningfully equivalent, and returns true.
How about this example:
Integer ic = 20; Integer id = 20; if(ic == id) System.out.println("They are the same objects."); if(ic.equals(id)) System.out.println("They are meaningfully equal.");
We'll have the following output from the run:
They are the same objects. They are meaningfully equal.
Surprisingly, something happened to the == while the equals() method seems to be working as we expected. Why is != telling us that ia and ib are different objects, when == is telling that ic and id are the same object?
What happened? It's all about saving memory!
In order to save memory, two instances of the following wrapper object created through boxing, will always be == when their primitive values are the same:
- Boolean
- Byte
- Character from \u0000 to \u007f (127 in decimal)
- Short and Integer from -128 to 127
Note that when we use == to compare a primitive to a wrapper, the wrapper will be unwrappered and the comparison will be primitive to primitive.
We'll look at three factors that can make overloading tricky:
- Widening
- Autoboxing
- Var-args
When a class has overloaded methods, one of the compiler's job is to decide which method to use when there is an invocation for the overloaded method. Let's look at the following example.
public class Overloaded { public static void main(String[] args) { byte b =2; short s = 2; long l = 2; float d = 2.0f; Overloaded o = new Overloaded(); o.go(b); o.go(s); o.go(l); o.go(d); } void go(int i) { System.out.println("int "); } void go(long l) { System.out.println("long "); } void go(double d) { System.out.println("double "); } }
The output from the run:
int int long double
The calls that use byte and short arguments are implicitly widened to match the version of the go() method that takes an int. The call with the long uses the long version of go() method and the call that uses a float is matched to the method that takes a double.
In all of the cases, when an exact match isn't found, the JVM uses the method with the smallest argument that is <wider than the parameter.
If we have only double version of go(), it will be used to match all four invocations of go().
public class Overloaded { public static void main(String[] args) { byte b =2; short s = 2; long l = 2; float d = 2.0f; Overloaded o = new Overloaded(); o.go(b); o.go(s); o.go(l); o.go(d); } /* void go(int i) { System.out.println("int "); } void go(long l) { System.out.println("long "); } */ void go(double d) { System.out.println("double "); } }
All of the calls uses go() which takes a double as we expected.
double double double double
Let's modify the code by adding boxing.
public class OverloadedWithBoxing { public static void main(String[] args) { int i = 2010; OverloadedWithBoxing o = new OverloadedWithBoxing(); o.go(i); } void go(Integer i) { System.out.println("Integer "); } void go(long l) { System.out.println("long "); } }
Which go() will be invoked?
If the only version of the go() method is the one that takes an Integer, then Java 5's boxing capability would allow the invocation of go() to succeed. Similarly, if only the long version existed, the compiler would use it for the invocation of the go().
The question is, given that both methods exist, which one will be used? In other words, does the compiler think that widening a primitive parameter is more desirable that performing an autoboxing operation? The answer is that the compiler will choose widening over boxing. So, the output is:
long
Widening beats boxing
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization