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 Chapter 2: Everything is an Object
73
taken by C and C++. That is, instead of creating the variable using new, an “automatic”
variable is created that is not a handle. 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 so portable.
Primitive type
Size
Minimum
Maximum
Wrapper
type
boolean
1-bit
–
–
Boolean
char
16-bit
Unicode 0
Unicode 216- 1
Character
byte
8-bit
-128
+127
Byte1
short
16-bit
-215
+215 – 1
Short1
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
–
–
–
Void1
All numeric types are signed, so don’t go looking for unsigned types.
The primitive data types also have “wrapper” classes for them. That means that if you want to make a non-primitive object on the heap to represent that primitive type, you use the associated wrapper. 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 1.1 has added 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.
1 In Java version 1.1 only, not in 1.0.
74
Thinking in Java
www.BruceEckel.com
Consult your online documentation for details about the constructors and methods you can call for these two classes.
Arrays in Java
Virtually all programming languages support arrays. Using arrays in C and C++ is perilous because those arrays are only blocks of memory. If a program accesses the array outside of its memory block or uses the memory before initialization (common programming errors) there will be unpredictable results.2
One of the primary goals of Java is safety, so many of the problems that plague programmers in C and C++ are not repeated in Java. A Java array is guaranteed to be initialized and cannot be accessed outside of its range. The range checking comes at the price of having a small amount of memory overhead on each array as well as verifying the index at run time, but the assumption is that the safety and increased productivity is worth the expense.
When you create an array of objects, you are really creating an array of handles, and each of those handles is automatically initialized to a special value with its own keyword: null.
When Java sees null, it recognizes that the handle in question isn’t pointing to an object.
You must assign an object to each handle before you use it, and if you try to use a handle that’s still null, the problem will be reported at run-time. Thus, typical array errors are prevented in Java.
You can also create an array of primitives. Again, the compiler guarantees initialization because it zeroes the memory for that array.
Arrays will be covered in detail in later chapters.
You never need to
destroy an object
In most programming languages, the concept of the lifetime of a variable occupies a significant portion of the programming effort. How long does the variable last? If you are supposed to destroy it, when should you? Confusion over variable lifetimes can lead to a lot of bugs, and this section shows how Java greatly simplifies the issue by doing all the cleanup work for you.
Scoping