, ,

Widening and Narrowing Reference Conversions – Basic Elements, Primitive Data Types, and Operators

Widening and Narrowing Reference Conversions

The subtype–supertype relationship between reference types determines which conversions are permissible between them (§5.1, p. 191). Conversions up the type hierarchy are called widening reference conversions (also called upcasting). Such a conversion converts from a subtype to a supertype:

Click here to view code image

Object obj = “Upcast me”;  // (1) Widening: Object <—– String

Conversions down the type hierarchy represent narrowing reference conversions (also called downcasting):

Click here to view code image

String str = (String) obj; // (2) Narrowing requires cast: String <—– Object

A subtype is a narrower type than its supertype in the sense that it is a specialization of its supertype. Contexts under which reference conversions can occur are discussed in §5.8, p. 261.

Widening reference conversions are usually done implicitly, whereas narrowing reference conversions usually require a cast, as illustrated in the second declaration statement above. The compiler will reject casts that are not legal or will issue an unchecked warning under certain circumstances if type-safety cannot be guaranteed.

Widening reference conversions do not require any runtime checks and never result in an exception during execution. This is not the case for narrowing reference conversions, which require a runtime check and can throw a ClassCastException if the conversion is not legal.

Boxing and Unboxing Conversions

Boxing and unboxing conversions allow interoperability between primitive values and their representation as objects of the wrapper types (§8.3, p. 429).

A boxing conversion converts the value of a primitive type to a corresponding value of its wrapper type, and an unboxing conversion converts the value of a wrapper type to a value of its corresponding primitive type. Both boxing and unboxing conversion are applied implicitly in the right context, but the wrapper classes also provide the static method valueOf() to explicitly box a primitive value in a wrapper object, and the method primitiveTypeValue() to explicitly unbox the value in a wrapper object as a value of primitiveType.

Click here to view code image

Integer iRef = 10;                   // (1) Implicit boxing: Integer <—– int
Double dRef = Double.valueOf(3.14);  // (2) Explicit boxing: Double <—– double

int i = iRef;                      // (3) Implicit unboxing: int <—– Integer
double d = dRef.doubleValue();     // (4) Explicit unboxing: double <—– Double

At (1) above, the int value 10 results in an object of type Integer implicitly being created; this object contains the int value 10. We say that the int value 10 has been boxed in an object of the wrapper type Integer. This implicit boxing conversion is also called autoboxing. An explicit boxing by the valueOf() method of the wrapper classes is used at (2) to box a double value.

Unboxing conversion is illustrated by (3) and (4) above. Implicit unboxing is applied at (3) to unbox the value in the Integer object, and explicit unboxing is applied at (4) by calling the doubleValue() method of the Double class.

Note that both boxing and unboxing are done implicitly in the right context. Boxing allows primitive values to be used where an object of their wrapper type is expected, and unboxing allows the converse. Unboxing makes it possible to use a Boolean wrapper object as a boolean value in a boolean expression, and to use an integral wrapper object as an integral primitive value in an arithmetic expression. Unboxing a wrapper reference that has the null value results in a NullPointer-Exception. Ample examples of boxing and unboxing can be found in this chapter and in §5.8, p. 261.

Related Posts