"Since developers could come up with classes that describe numbers, they decided to be creative, like real developers."

"First, they came up with an abstract Number class, from which Byte, Short, Integer, Long, Float, and Double are derived. It has methods that help convert numbers to other numeric types."

Methods of the Number class
1
int intValue()
2
long longValue()
3
float floatValue()
4
double doubleValue()
5
byte byteValue()
6
short shortValue()

"Right. After all, you can't write this:"

Long x = 100000;
Integer y = (Integer) x;

"Yeah, these types are not primitives. That's why we use the methods of the Number class:"

Long x = 100000;
Integer y = x.intValue();

"But there are still a couple of things to consider. Because Integer is not an int, Integer objects can't be compared with the classic «==» operator."

Comparing primitive types
int x = 500;
int y = 500;
x == y; //true
Comparing non-primitive types
Integer x = 500;
Integer y = 500;
x == y; //false
x.equals(y); //true

"Exactly. Somehow I didn't think of that right away."

"But there's more."

"You're shorting my circuits! What else is there?"

"When we assign an int value to an Integer variable, the Integer.valueOf method is called:"

Code What really happens
Integer x = 5;
Integer x = Integer.valueOf(5);

"Yeah, I already understood that from the example above."

"But, the valueOf function does not always create a new Integer object."

"Uh, what do you mean «not always»?"

"It caches values from -128 to 127."

Code What really happens Description
Integer x = 300;
Integer y = 300;
Integer z = 300;
Integer x = Integer.valueOf(300);
Integer y = Integer.valueOf(300);
Integer z = Integer.valueOf(300);
Variable x, y, and z contain references to different objects
Integer x = 100;
Integer y = 100;
Integer z = 100;
Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
Integer z = Integer.valueOf(100);
Variables x, y, and z contain references to the same object.
Integer x = new Integer(10)
Integer y = new Integer(10)
Integer z = 10;
Integer t = 10;
Integer x = new Integer(10)
Integer y = new Integer(10)
Integer z = Integer.valueOf(10);
Integer t = Integer.valueOf(10);
Variables z and t contain references to the same object.

"In other words, the situation is this:"

1) If we write «new Integer()», then we are guaranteed to get a new object.

2) If we call Integer.valueOf(), explicitly or through autoboxing, then the method may return a new object or a cached object if the number argument is in the range from -128 to 127.

"What's so terrible about the method returning an object from the cache?"

"Never mind. You just need to know that sometimes, when you're not expecting it, objects might be equal. Everything with equality is complicated. If we compare a primitive with a non-primitive, then they are compared as primitives:"

Comparison problem
int x = 300;
Integer y = 300;
Integer z = 300;

x == y; //true (comparison based on primitive value)
x == z; //true (comparison based on primitive value)
y == z; //false (comparison based on references)
An even more interesting example. The cache enters the picture here
int x = 100;
Integer y = 100;
Integer z = 100;

x == y; //true (comparison based on primitive value)
x == z; //true (comparison based on primitive value)
y == z; //true (comparison based on references; they point to the same object)
But the cache is not involved here
int x = 100;
Integer y = new Integer(100);
Integer z = 100;

x == y; //true (comparison based on primitive value)
x == z; //true (comparison based on primitive value)
y == z; //false (comparison based on references; they point to different objects)

"Great... And how will I memorize all this?"

"You don't need to memorize this. You just need to understand how this is all organized and what actually happens when a primitive and its non-primitive counterpart come into play."

"I also recommend that you look at the methods of the Integer class. It has quite a few good and useful methods. You've even used one of them quite often."

"Yeah, I remember. Integer.parseInt();"