What you have to understand about primitives is that they are...well...primitive. In other words, there's no long-lived type stored about that data--the type is completely determined by the way you're accessing it.
Example time.
Do x, b, and c all refer to the same data in memory? The answer is no. If I change the value of x by writing x++, for instance, b and c will remain unaltered and still point to the bit
pattern that represents 10. If I refer to x, I'm referring to an int. If I refer to b, a byte, and c, a char. That's it. The type of data literally changed when I coerced it into doing so with the type casts.
You always know what the type of your primitive data is because Java is strongly typed, and the language forces you to confer type upon a particular bit pattern in memory before you work with it. For instance, if you try to pass a char into a method that takes an int, the compiler will complain. If you typecast that char to an int when you pass it in, then it shows up to that method as an int and it gets treated as an int from there on out. Indeed, there's a new copy of that bit pattern floating around now, and it IS an int in every way.
This is vastly different from the way objects are handled. With objects, everything is passed around by reference. Furthermore, there is a distinction between "class" and "type" that it's important for every Java developer to know and understand. The class of an object is determined when that object is instantiated, and that object can never, ever change its class. It's born of a certain class, it lives as that class, and gets garbage collected as that class. It cannot change.
Type, on the other hand, is a different matter for objects. Objects themselves may be of a particular class that cannot change, but an object's type can change from moment to moment. The whole concept of "type" is not really an intrinsic part of an object...rather, type is intrinsic to a reference. The kind of reference used to refer to an object is what confers upon that object a "type".
Example:
On line 1, an Integer object is created. Because the new operator was called, it created an object on the heap of class Integer. You'll often hear people confuse things by saying it created an object of "type" Integer--which is not true. Well...it is true, but it's not the *whole* story. The whole story is, it created an object of class Integer, but of type Integer, Number, and Object. An object can be of many types at once...but only one class.
So we've created an object of class Integer. We immediately store a reference to that object in i, a reference of type Integer. So on that line, we are referring to an object of class Integer and conferring upon it the type Integer by using the reference i.
In the next line, we are referring to an object of class Integer with a reference of type Number. This reference, n, confers a different type upon the same object (still of the same class, though). Then we do it again on the next line, except now the same Integer object is playing the type of Object. No matter what reference you use to that object, though, if you were to get the class name, it'd come back "java.lang.Integer" because class doesn't change.
This is not the case with primitives, though. When you create a new "reference" (it's not really a reference, of course) to a primitive, you've copied that bit pattern from one part of memory to another and told the JVM and compiler to treat that bit pattern as int, or char, or byte, or float, or whatever. A primitive variable is not really a "reference" because it doesn't "refer" to anything--there's no level of indirection from the variable to the data. The variable is itself both a name and a type for that very bit pattern, and they are locked forever in one-to-one-to-one correspondence (variable-to-name-to-type).
sev