Java Reference
In-Depth Information
Now, here's a surprise: consider the following snippet of code. This time you are relying on autoboxing.
Integer aaa = 100; // Boxing - Integer.valueOf(100)
Integer bbb = 100; // Boxing - Integer.valueOf(100)
Integer ccc = 505; // Boxing - Integer.valueOf(505)
Integer ddd = 505; // Boxing - Integer.valueOf(505)
System.out.println(aaa == bbb); // will print true
System.out.println(aaa == ccc); // will print false
System.out.println(ccc == ddd); // will print false
You used
aaa
,
bbb
,
ccc
, and
ddd
as reference types. How is
aaa == bbb true
whereas
ccc == ddd false
?
All right. This time, there is no surprise coming from the autoboxing feature. Rather, it is coming from the
Integer.
valueOf()
method. For all values between -128 and 127, the
Integer
class caches
Integer
object references. The
cache is used when you call its
valueOf()
method. For example, if you call
Integer.valueOf(100)
twice, you get
the reference of the same
Integer
object from the cache that represents the
int
value of 100. However, if you call
Integer.valueOf(n)
, where
n
is outside the range -128 to 127, a new object is created for every call. This is the reason
that
aaa
and
bbb
have the same reference from the cache, whereas
ccc
and
ddd
have different references.
Byte
,
Short
,
Character
and
Long
classes also cache object references for values in the range -128 to 127.
Collections and Autoboxing/Unboxing
Autoboxing/unboxing helps you work with collections. Collections work only with reference types. You cannot use
primitive types in collections. If you want to store primitive types in a collection, you must wrap the primitive value
before storing it, and unwrap it after retrieving it. Suppose you have a
List
and you want to store integers in it. This is
how you would do it:
List list = new ArrayList();
list.add(new Integer(101));
Integer a = (Integer)list.get(0);
int aValue = a.intValue();
You are back to square one. The
add()
and
get()
methods of the
List
interface work with
Object
type, and
you had to resort to wrapping and unwrapping the primitive types again. The autoboxing/unboxing may help you in
wrapping the primitive type to a reference type, and the above code may be rewritten as
List list = new ArrayList();
list.add(101); // Autoboxing will work here
Integer a = (Integer)list.get(0);
int aValue = a.intValue();
/*int aValue = list.get(0); */ // autounboxing won't compile
Because the return type of the
get()
method is
Object
, the last statement in this snippet of code would not
work. Note that unboxing happens from a primitive wrapper type (such as
Integer
) to its corresponding primitive
type (such as
int
). If you try to assign an
Object
reference type to an
int
primitive type, the autounboxing does not
happen. In fact, your code would not even compile, because
Object
to
int
conversion is not allowed.
Try the following code:
List<Integer> list = new ArrayList<>();
list.add(101); // autoboxing will work
int aValue = list.get(0); // autounboxing will work, too