1. Question - What the program would output?
We can immediately know the answer after we look at the source code.
2.2 What would be the output of the following program?
int
i =
127
;
boolean
b = (Integer.valueOf(i) == Integer.valueOf(i));
System.err.println(b);
i =
128
;
b = (Integer.valueOf(i) == Integer.valueOf(i));
System.err.println(b);
We can immediately know the answer after we look at the source code.
public
static
Integer valueOf(
int
i) {
if
(i >= -
128
&& i <= IntegerCache.high)
return
IntegerCache.cache[i +
128
];
else
return
new
Integer(i);
}
We can know it doesn't cache all Integer values, as this may consume too much memory, so it just caches the numbers between [-128, 127] in the static IntegerCache class, for other int numbers, each time it would return a new Integer. Class Long also only caches the numbers between [-128, 127].
The output of the previous program would be obvious now: true and false.
2. Autobox and Auto-unbox
2. 1 How is it implemented in JDK?
Simply put, when we call "Integer wrapper = 2;", the java compile would translate it to "Integer wrapper = Integer.valueOf(wrapper);".
When we call "int i = wrapper;", the java compile would translate it to "int i = wrapper.intValue();".
You can verify this by using javap to look. at the compiled java class: javap -c IntegerTester.
Long.valueOf(0L).equals(0)?
2.2 What would be the output of the following program?
Long l = 0L;
Integer i =
0
;
System.out.println(l.equals(i));
System.out.println(i.equals(l));
So let's look at the JDK source code again:
public
final
class
Integer
extends
Number
implements
Comparable {
public
boolean
equals(Object obj) {
if
(obj
instanceof
Integer) {
return
value == ((Integer)obj).intValue();
}
return
false
;
}
}
public
final
class
Long
extends
Number
implements
Comparable {
public
boolean
equals(Object obj) {
if
(obj
instanceof
Long) {
return
value == ((Long)obj).longValue();
}
return
false
;
}
}
From the code, we can see if the type of parameter is not same, these method would return false.
So the output of previous program would be false, false.
Autobox and auto-unbox are good features, as it will convert the primitive type or wrapper type to the needed one, and we can write less code, but we should use it carefully, as usually, it may create object under the hood, if we are unaware of this, it may cause big performance penalty.
public
void
test(Integer i) {
while
(i <
0
) {
--i;
}
}
In the previous program, in each step, JVM actually does this: it calls i.intValue(), subtracts it by one, and then create a new Integer value.
For JVM, it would be same as:
So in each step, we would unnecessary create one Integer value and call intValue methods twice.
Try to use javap to look at the compiled class file.
If we know this, we can change our code like the below, it would be faster.
public
void
test(Integer i) {
int
j = i;
while
(j <
0
) {
--j;
}
i = j;
}
In our code, it's to better use primitive type as often as possible.
In Integer class there are many other interesting and useful methods, some methods are listed below, are they cool and a little confusing? Try to figure it out.
public
final
class
Integer
extends
Number
implements
Comparable {
public
static
int
reverseBytes(
int
i) {
return
((i >>>
24
) ) |
((i >>
8
) &
0xFF00
) |
((i <<
8
) &
0xFF0000
) |
((i <<
24
));
}
public
static
int
reverse(
int
i) {
// HD, Figure 7-1
i = (i &
0x55555555
) <<
1
| (i >>>
1
) &
0x55555555
;
i = (i &
0x33333333
) <<
2
| (i >>>
2
) &
0x33333333
;
i = (i &
0x0f0f0f0f
) <<
4
| (i >>>
4
) &
0x0f0f0f0f
;
i = (i <<
24
) | ((i &
0xff00
) <<
8
) |
((i >>>
8
) &
0xff00
) | (i >>>
24
);
return
i;
}
public
static
int
bitCount(
int
i) {
// HD, Figure 5-2
i = i - ((i >>>
1
) &
0x55555555
);
i = (i &
0x33333333
) + ((i >>>
2
) &
0x33333333
);
i = (i + (i >>>
4
)) &
0x0f0f0f0f
;
i = i + (i >>>
8
);
i = i + (i >>>
16
);
return
i &
0x3f
;
}
}