Wednesday, February 2, 2011

Chapter 19: Using Wrapper Classes and Boxing

The wrapper classes in the Java API serve two primary purposes:
• To provide a mechanism to “wrap” primitive values in an object so that the primitives can be included in activities reserved for objects, like being added to Collections, or returned from a method with an object return value.
• To provide an assortment of utility functions for primitives. Most of these functions are related to various conversions: converting primitives to and from String objects, and converting primitives and String objects to and from different bases (or radix), such as binary, octal, and hexadecimal.

An Overview of the Wrapper Classes

There is a wrapper class for every primitive in Java. For instance, the wrapper class for int is Integer, the class for float is Float, and so on. Remember that the primitive name is simply the lowercase name of the wrapper except for char, which maps to Character, and int, which maps to Integer.

The Wrapper classes for each of the primitive types is as follows:
1. boolean – Boolean
2. byte – Byte
3. char – Character
4. double – Double
5. float – Float
6. int – Integer
7. long – Long
8. short – Short

A point to note here is that, the wrapper classes for numeric primitives have the capability to convert any valid number in string format into its corresponding primitive object. For ex: “10” can be converted into an Integer by using the below line

Integer intVal = new Integer(“10”);

I can do the same for all numeric types like long, short etc. But, if I pass an invalid value I will get a “NumberFormatException” Ex:

Integer intVal = new Integer(“Haha”);

The Wrapper Constructors

All of the wrapper classes except Character provide two constructors: one that takes a primitive of the type being constructed, and one that takes a String representation of the type being constructed—for example

Integer i1 = new Integer(42);
Integer i2 = new Integer("42");

or
Float f1 = new Float(3.14f);
Float f2 = new Float("3.14f");

The Character class provides only one constructor, which takes a char as an argument—for example

Character c1 = new Character('c');

The constructors for the Boolean wrapper take either a boolean value true or false, or a String. If the String’s case-insensitive value is “true” the Boolean will be true—any other value will equate to any other value will equate to false. Until Java 5, a Boolean object couldn’t be used as an expression in a boolean test—for instance

Boolean b = new Boolean("false");
if (b) // won't compile, using Java 1.4 or earlier

As of Java 5, a Boolean object can be used in a boolean test, because the compiler will automatically “unbox” the Boolean to a boolean.

The valueOf() Methods

The two static valueOf() methods provided in most of the wrapper classes give you another approach to creating wrapper objects. Both methods take a String representation of the appropriate type of primitive as their first argument, the second method (when provided) takes an additional argument, int radix, which indicates in what base (for example binary, octal, or hexadecimal) the first argument is represented—for example

Integer i2 = Integer.valueOf("101011", 2);
// converts 101011 to 43 and assigns the value 43 to the object i2
or
Float f2 = Float.valueOf("3.14f");
// assigns 3.14 to the object f2

Using Wrapper Conversion Utilities

As said at the beginning of the chapter, a wrapper’s second big function is converting stuff. The following methods are the most commonly used, and are the ones you’re most likely to see on the test.

xxxValue()

When you need to convert the value of a wrapped numeric to a primitive, use one of the many xxxValue() methods. All of the methods in this family are no-arg methods.

Each numeric value’s wrapper has 6 xxxValue() methods to convert the numeric value into the other possible numeric data types. Which totally makes 36 xxxValue() methods. That is, an Integer Wrapper has intValue(), shortValue(), doubleValue() and so on for a total of 6 methods.
This is provided to us, so that any numeric wrapper can be converted to any primitive numeric type—for example

Integer i2 = new Integer(42); // make a new wrapper object
byte b = i2.byteValue();
// convert i2's value to a byte primitive
short s = i2.shortValue();
// another of Integer's xxxValue methods
double d = i2.doubleValue();
// yet another of Integer's xxxValue methods

parsexxx() and valueOf()

The six parseXxx() methods (one for each numeric wrapper type) are closely related to the valueOf() method that exists in all of the numeric wrapper classes. Both parseXxx() and valueOf() take a String as an argument, throw a NumberFormatException if the String argument is not properly formed, and can convert String objects from different bases (radix), when the underlying primitive type is any of the four integer types. The difference between the two methods is as follows:

• parseXxx() returns the named primitive.
• valueOf() returns a newly created wrapped object of the type that invoked the method.
Below is an example of these methods in action:
double d = Double.parseDouble("3.14");
// convert a String to a primitive

Long L = Long.valueOf("101010", 2);
// binary String to Long object

toString()

Class Object, the top-most class, has a toString() method. Since we know that all other Java classes inherit from class Object, we also know that all other Java classes have a toString() method. The idea of the toString() method is to allow you to get some meaningful representation of a given object. All of the wrapper classes have a no-arg, nonstatic, instance version of toString(). This method returns a String with the value of the primitive wrapped in the object—for instance

Double d = new Double("3.14");
System.out.println("d = "+ d.toString() ); // result is d = 3.14

All of the numeric wrapper classes provide an overloaded, static toString() method that takes a primitive numeric of the appropriate type (Double.toString() takes a double, Long.toString() takes a long, and so on) and, returns a String:
String d = Double.toString(3.14); // d = "3.14"

toxxxString() (Binary, Hexadecimal, Octal)

The Integer and Long wrapper classes let you convert numbers in base 10 to other bases. These conversion methods, toXxxString(), take an int or long, and return a String representation of the converted number, for example,
String s3 = Integer.toHexString(254); // convert 254 to hex
System.out.println("254 is " + s3); // result: "254 is fe"

String s4 = Long.toOctalString(254); // convert 254 to octal
System.out.print("254(oct) ="+ s4); // result: "254(oct) =376"

If you can remember the differences between xxxValue(), parseXxx(), and valueOf() methods, you should do well on this part of the exam.

Autoboxing

New to Java 5 is a feature known variously as: autoboxing, auto-unboxing, boxing, and unboxing. We’ll stick with the terms boxing and unboxing. Boxing and unboxing make using wrapper classes more convenient. In the old, pre–Java 5 days, if you wanted to make a wrapper, unwrap it, use it, and then rewrap it, you might do something like this:

Integer y = new Integer(111);
int x = y.intValue();
x++;
y = new Integer(x);
System.out.println("y = " + y);

Now, with new and improved Java 5 you can say
Integer y = new Integer(111);
y++;

System.out.println("y = " + y);

Both examples produce the same output:
y = 112

And yes, you read that correctly. The code appears to be using the postincrement operator on an object reference variable! But it’s simply a convenience. Behind the scenes, the compiler does the unboxing and reassignment for you.

Boxing, == and equals()

Let us start with the examples to explain the behavior of == and equals() with respect to wrapper classes and Boxing.
Integer i1 = 1000;
Integer i2 = 1000;
if(i1 != i2) System.out.println("different objects");
if(i1.equals(i2)) System.out.println("meaningfully equal");

Produces the output:
different objects
meaningfully equal

It’s just two wrapper objects that happen to have the same value. Because they have the same int value, the equals() method considers them to be “meaningfully equivalent”, and therefore returns true. How about this one:

Integer i3 = 10;
Integer i4 = 10;
if(i3 == i4) System.out.println("same object");
if(i3.equals(i4)) System.out.println("meaningfully equal");

This example produces the output:

same object
meaningfully equal

Whoops! The equals() method seems to be working, but what happened with == and != ? Why is != telling us that i1 and i2 are different objects, when == is saying that i3 and i4 are the same object? In order to save memory, two instances of the following wrapper objects (created through boxing), will always be == when their primitive values are the same:

• Boolean
• Byte
• Character from \u0000 to \u007f (7f is 127 in decimal)
• Short and Integer from - 128 to 127

Note: When == is used to compare a primitive to a wrapper, the wrapper will be unwrapped and the comparison will be primitive to primitive.

Where Boxing Can Be used

As we discussed earlier, it’s very common to use wrappers in conjunction with collections. Any time you want your collection to hold objects and primitives, you’ll want to use wrappers to make those primitives collection-compatible. The general rule is that boxing and unboxing work wherever you can normally use a primitive or a wrapped object.

Exam Tip: Remember, wrapper reference variables can be null. That means that you have to watch out for code that appears to be doing safe primitive operations, but that could throw a NullPointerException:
class BoxingExample {
static Integer x;
public static void main(String [] args) {
doBox(x);
}
static void doBox(int z) {
int z2 = 5;
System.out.println(z2 + z);
} }

This code compiles fine, but the JVM throws a NullPointerException when it attempts to invoke doBox(x), because x doesn’t refer to an Integer object, so there’s no value to unbox.

Previous Chapter: Chapter 18 - Arrays

Next Chapter: Chapter 20 - Overloading in Detail

1 comment:

  1. Must be error becuse you r using non static variable in static method z2.

    ReplyDelete

© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers