Tutorial Java SCJP – #15 Wrapper classes for primitive types

2 comments - This post in romanian

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.