In Java there are 2 important categories of data types: references and primitives. Most of the time, numeric values, chars and boolean values are used as primitives because it is more efficient as processing speed and memory requirements. Despite that, there are scenarios (like using Collections) when it is needed to store primitive values inside objects. For that, Java provides a set of classes used to wrap primitive values in an object.
Other topics that are part of this Java tutorial are accessible through Java 6 SCJP Tutorial – Contents.
Every primitive type has a wrapper class:
Primitive type |
Wrapper class |
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
Besides the main role (managing primitive values), wrapper classes contain a set of utility methods used to convert values to different types or to parse string values into numeric ones.
As an important rule, do not forget that these allow you to define objects (managed by references) which encapsulate primitive values.
How to define and create wrapper objects
Wrapper objects are created using:
- the class constructor and the new operator;
- the static method: valueOf().
With the except of Character, the rest of wrapper classes provide constructors that can create an object based on a numeric value or a String, like this:
Integer intObject1 = new Integer(34); Integer intObject2 = new Integer("35"); Boolean boolValue1 = new Boolean("true"); Boolean boolValue2 = new Boolean(true); Character charObject = new Character('a'); //the only way
The Boolean class constructor defines a constructor that accepts a String value which is interpreted as true only for the case-insensitive value “true” (like “True”, “TRUE”, “TrUe”, …). Any other value is converted into false:
Boolean boolValue1 = new Boolean("true"); //true Boolean boolValue2 = new Boolean(true); //true Boolean boolValue3 = new Boolean("True"); //true Boolean boolValue4 = new Boolean("ZZZ"); //false
The valueOf() method has 2 forms that receive a String and a String with a radix representing the base for the wanted numeric value:
Integer intObject3 = Integer.valueOf("36"); Integer intObject4 = Integer.valueOf("1001", 2); //9 in base 2
Utility methods for wrapper classes
Being classes, wrappers also define a set of utility methods used to process numeric values:
[byte|short|int|long|float|double]Value() – each wrapper class has 6 methods of this type used to convert the current object value to any primitive numeric type:
Float floatObject = new Float(520.3f); byte byteValue = floatObject.byteValue(); //it is 8 short shortValue = floatObject.shortValue(); //it is 520
parse[Byte|Short|Int|Long|Float|Double]() – each wrapper class has a static method (Integer has parseInt) used to convert a String into a primitive value (same type as the method name); as valueOf() the method has 2 forms because it accepts also the base for the numeric conversion; if the string is not valid, the method throws a NumberFormatException:
int intValue = Integer.parseInt("234"); long longValue = Integer.parseInt("ffff", 16); //65535 in base 16 int value = Integer.parseInt("12a"); //NumberFormatException
toString() – method inherited from Object (as any other Java class) that return a string representation of the value; it is called implicitly; numeric wrapper classes provide also a static toString() method; Integer and Long provide a third form of toString(), that is static and that allow to convert any base 10 value to another radix base:
Double doubleObject = new Double(123.4); System.out.println("double value = " + doubleObject.toString()); System.out.println("boolean value " + Boolean.toString(true)); System.out.println("65000 in hex is "+Long.toString(65000, 16));
to[Binary|Octal|Hexadecimal]String() – static methods defined only in Integer and Long for converting base 10 numbers to base 2, 8 or 16:
String hexValue = Integer.toHexString(32); String octValue = Integer.toOctalString(32); String bynaryValue = Integer.toBinaryString(32); System.out.println("32 is " + hexValue + " (16), " + octValue + "(8) or " + bynaryValue + "(2)");
What is autoboxing and unboxing
Boxing is a feature available since Java 1.5 that allow programmers to use wrapper classes in a more convenient way. Before that, you must write a lot of code to do something simple like transferring values between wrappers and primitives:
Integer intObj1 = new Integer(23); int intPrimitive = intObj1.intValue(); intPrimitive += 10; Integer intObj2 = new Integer(intPrimitive);
With autoboxing, the same thing is done with ease because the compiler manages the conversions for us
Integer intObj1 = 23; //autoboxing int intPrimitive = intObj1; //unboxing intPrimitive++; Integer intObj2 = intPrimitive; //autoboxing
Boxing is the process of wrapping a primitive inside an object. Autoboxing is the process done without explicit call to constructors. Unboxing is the reverse process that allows extracting a value without an explicit call to [byte|short|int|long|float|double]Value() methods.
Because, before Java 1.5 you don’t have autoboxing and unboxing, it wasn’t possible to (now you can) use a Boolean object in a conditional statement:
Boolean boolValue = true; if(boolValue) //unboxing System.out.println("It's true !");
SCJP topic – Wrapper objects are managed by references
Because of autoboxing and unboxing, you can get a false impressions that wrapper objects can be used as primitives. But, for the SCJP exam, do not forget that wrappers ARE OBJECTS, meaning that are managed by references. So, remember that:
- = does a shallow copy, copies values between references
- == compares references values
- equals() is used to compare objects values
Using previous rules, the next example:
Integer intObject1 = 2300; //autoboxing Integer intObject2 = intObject1; //shallow copy if(intObject1 == intObject2) System.out.println("Same object !"); else System.out.println("Different objects !"); Integer intObject3 = 2300; //autoboxing Integer intObject4 = 2300; //autoboxing //compare using == if(intObject3 == intObject4) System.out.println("Same object !"); else System.out.println("Different objects !"); //compare using equals if(intObject3.equals(intObject4)) System.out.println("Objects with same value !"); else System.out.println("Different values !");
will print:
Same object ! Different objects ! Objects with same value !
SCJP topic – Wrapper classes are immutable
For a detailed description of the immutable concept see Tutorial Java SCJP – #12 Immutable, String and Integer
The conclusion is that every time you change the value of a wrapper object it is created a new object:
Integer intObject1 = 2300; //autoboxing Integer intObject2 = intObject1; //shallow copy //increment the value intObject1++; //because it is immutable, you get a new object System.out.println(intObject1); if(intObject1 == intObject2) System.out.println("Same object"); else System.out.println("Different objects");
Previous example will print:
2301 Different objects
Behind the scenes, the compiler unwrap the object into a primitive, changes its value and re-wrap it into a new object. The reference will receive the address of the newly created object.
SCJP topic – Boolean, Byte, Character, Short and Integer Wrappers can be compared with == for small values
In terms of efficiency, Java considers that small integer values are used with a high frequency and for that Boolean, Byte, Character, Short and Integer objects can be compared at value level with == instead of equals().
So two Boolean, Byte, Character, Short and Integer instances will return true when compared with == when their values are the same. This rule is true for:
- any Boolean object
- any Byte object
- Character objects with values between \u0000 to \u007f (\u007f is 127 in decimal)
- Short and Integer from –128 to 127
The next example:
Integer intObject1 = 10; //autoboxing Integer intObject2 = 10; //autoboxing if(intObject1 == intObject2) System.out.println("Equal values"); else System.out.println("Different values"); if(intObject1.equals(intObject2)) System.out.println("Equal values"); else System.out.println("Different values");
will print.
Equal values Equal values
In the previous example,if you use values greater than 127 you will get a different output.
For the SCJP exam do not forget:
- all wrapper classes are immutable;
- the wrapper reference must be initialized before you use it;
- using == between wrapper references if tricky (watch out for small value)
- boxing and unboxing is implemented by the compiler
Other topics that are part of this Java tutorial are accessible through Java 6 SCJP Tutorial – Contents.