Non-RAM storage. If data lives completely outside a program, it can
exist while the program is not running, outside the control of the program. The
two primary examples of this are streamed objects, in which objects are
turned into streams of bytes, generally to be sent to another machine, and
persistent objects, in which the objects are placed on disk so they will
hold their state even when the program is terminated. The trick with these types
of storage is turning the objects into something that can exist on the other
medium, and yet can be resurrected into a regular RAM-based object when
necessary. Java provides support for lightweight persistence, and future
versions of Java might provide more complete solutions for persistence.
Special case: primitive types
One group of types, which you’ll use quite often in your programming, gets special treatment. You can think of these as “primitive” types. The reason for the special treatment is that to create an object with new—especially a small, simple variable—isn’t very efficient, because new places objects on the heap. For these types Java falls back on the approach taken by C and C++. That is, instead of creating the variable by using new, an “automatic” variable is created that is not a reference. The variable holds the value, and it’s placed on the stack, so it’s much more efficient.
Java determines the size of each primitive type. These sizes don’t change from one machine architecture to another as they do in most languages. This size invariance is one reason Java programs are portable.
Primitive type
|
Size
|
Minimum
|
Maximum
|
Wrapper type
|
boolean
|
—
|
—
|
—
|
Boolean
|
char
|
16-bit
|
Unicode 0
|
Unicode 216- 1
|
Character
|
byte
|
8-bit
|
-128
|
+127
|
Byte
|
short
|
16-bit
|
-215
|
+215—1
|
Short
|
int
|
32-bit
|
-231
|
+231—1
|
Integer
|
long
|
64-bit
|
-263
|
+263—1
|
Long
|
float
|
32-bit
|
IEEE754
|
IEEE754
|
Float
|
double
|
64-bit
|
IEEE754
|
IEEE754
|
Double
|
void
|
—
|
—
|
—
|
Void
|
All numeric types are signed, so don’t look for unsigned types.
The size of the boolean type is not explicitly specified; it is only defined to be able to take the literal values true or false.
The “wrapper” classes for the primitive data types allow you to make a nonprimitive object on the heap to represent that primitive type. For example:
char c = 'x';
Character C = new Character(c);
Or you could also use:
Character C = new Character('x');
The reasons for doing this will be shown in a later chapter.
High-precision numbers
Java includes two classes for performing high-precision arithmetic: BigInteger and BigDecimal. Although these approximately fit into the same category as the “wrapper” classes, neither one has a primitive analogue.
Both classes have methods that provide analogues for the operations that you perform on primitive types. That is, you can do anything with a BigInteger or BigDecimal that you can with an int or float, it’s just that you must use method calls instead of operators. Also, since there’s more involved, the operations will be slower. You’re exchanging speed for accuracy.
BigInteger supports arbitrary-precision integers. This means that you can accurately represent integral values of any size without losing any information during operations.
BigDecimal is for arbitrary-precision fixed-point numbers; you can use these for accurate monetary calculations, for example.
Consult the JDK documentation for details about the constructors and methods you can call for these two classes.