Reference
Primitive types are considered primitives if and only if they are of type double
, float
, int
, long
, and so on.
Reference types are any type that uses an "Object" to store data. When you are creating in class, you're really creating a reference type "in disguise." Some examples of reference types are String
, Double
, Integer
, and so on.
So, as far as types go, when you compare float x
to Float y
, you're really comparing two different types!
In Java, the ==
's operator, most of the time, to compare only objects of equal type. Sometimes, however, the language will permit comparison of other types, such as x == y
in the case that x
is a primitive and y
is a reference type (as defined above).
When the comparison between x
and y
is performed an operation called boxing and unboxing is performed. But to understand boxing, you have to understand the difference between primitive types and reference types in terms of memory semantics. (Don't let that scare you!)
Primitive types are stored in a memory location called the stack, which is fast and not very flexible in terms of fragmented access. It's pretty easy.
Reference types are different though: when a reference type is instantiated using the new
operator (which is called implicitly when doing Float x = <something>;
-- that is, Float x = <something>;
is turned into Float x = new Float(<something>);
) So when a Float
or other reference type is instantiated, the object is created and stored on the heap, but the pointer to that object (which is on the heap) is stored in the stack.
This means that in order to retrieve the value that is stored in x
, the computer must use the address stored on the stack, and go to that memory address in the heap.
We use the heap to store reference types because the stack is not very good at something called "dynamic memory allocation," which is where memory is allocated and deallocated without concern to other objects around it.
Now for boxing and unboxing:
Boxing (also called wrapping) is the process of taking a primitive type object and storing it as a reference type (so float x
becomes Float x
), so that those two objects are the same type. (It's kind of like wrapping a christmas present in paper) So, behind the scenes, Integer k = 6
is a kind of boxing (autoboxing)
Unboxing on the other hand is the opposite of unboxing, so you can call it unwrapping. Unboxing takes a "boxed" object and takes it from a reference type back to a primitive type, so the statements can work without too much hassle.:
Integer k = 6; //Boxing
int m = k; //Unboxing
What this really means, in terms of your question: in the code that you posted, autoboxing and unboxing occurred, which made the statement valid. The JVM was smart enough to do what you meant -- but that doesn't mean you should make a regular habit of it, because boxing and unboxing can have a serious impact on the performance of your code!
Also, if both x
and y
were Float
types, you'd be comparing references!
Good Luck!