There are a few important differences you should know between primitives and reference types. First, notice that all the primitive types have lowercase type names. All classes that come with Java begin with uppercase. Although not required, it is a standard practice, and you should follow this convention for classes you create as well.
Next, reference types can be used to call methods, assuming the reference is not null. Primitives do not have methods declared on them. In this example, we can call a method on reference since it is of a reference type. You can tell length is a method because it has () after it. See if you can understand why the following snippet does not compile:
Line 6 is gibberish. No methods exist on len because it is an int primitive. Primitives do not have methods. Remember, a String is not a primitive, so you can call methods like length() on a String reference, as we did on line 5.
Finally, reference types can be assigned null, which means they do not currently refer to an object. Primitive types will give you a compiler error if you attempt to assign them null. In this example, value cannot point to null because it is of type int:
int value = null; // DOES NOT COMPILE
String name = null;
But what if you don’t know the value of an int and want to assign it to null? In that case, you should use a numeric wrapper class, such as Integer, instead of int.
Each primitive type has a wrapper class, which is an object type that corresponds to the primitive. Table 1.7 lists all the wrapper classes along with how to create them.
TABLE 1.7 | Wrapper classes | ||
Wrapper class | |||
Primitive type | Wrapper class | inherits Number? | Example of creating |
boolean | Boolean | No | Boolean.valueOf(true) |
byte | Byte | Yes | Byte.valueOf((byte) 1) |
short | Short | Yes | Short.valueOf((short) 1) |
int | Integer | Yes | Integer.valueOf(1) |
long | Long | Yes | Long.valueOf(1) |
float | Float | Yes | Float.valueOf((float) 1.0) |
double | Double | Yes | Double.valueOf(1.0) |
char | Character | No | Character.valueOf(‘c’) |
There is also a valueOf() variant that converts a String into the wrapper class.
For example:
int primitive = Integer.parseInt(“123”); Integer wrapper = Integer.valueOf(“123”);
The first line converts a String to an int primitive. The second converts a String to an Integer wrapper class.
All of the numeric classes in Table 1.7 extend the Number class, which means they all come with some useful helper methods: byteValue(), shortValue(), intValue(), longValue(), floatValue(), and doubleValue(). The Boolean and Character wrapper classes include booleanValue() and charValue(), respectively.
As you probably guessed, these methods return the primitive value of a wrapper instance, in the type requested.
Double apple = Double.valueOf(“200.99”); | |||
System.out.println(apple.byteValue()); | // -56 | ||
System.out.println(apple.intValue()); | // | 200 | |
System.out.println(apple.doubleValue()); | // | 200.99 |
These helper methods do their best to convert values but can result in a loss of preci-sion. In the first example, there is no 200 in byte, so it wraps around to -56. In the sec-ond example, the value is truncated, which means all of the numbers after the decimal are dropped. In Chapter 5, we apply autoboxing and unboxing to show how easy Java makes it to work with primitive and wrapper values.
Some of the wrapper classes contain additional helper methods for working with num-bers. You don’t need to memorize these; you can assume any you are given are valid. For example, Integer has:
max(int num1, int num2), which returns the largest of the two numbers min(int num1, int num2), which returns the smallest of the two numbers sum(int num1, int num2), which adds the two numbers