THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

The types higher up the type hierarchy are said to be wider, or less specific, than the types lower down the
hierarchy. The lower types are said to be narrower, or more specific, than their supertypes. When you are
expecting a supertype and receive a subtype, a widening conversion takes place. Such a conversion causes the
subtype object to be treated as an instance of the supertype and can be checked at compile time. No action is
needed by the programmer in a widening conversion. Going the other waytaking a reference to a supertype
and converting it to a reference to a subtypeis known as a narrowing conversion. Narrowing conversions must
be explicitly requested using the cast operator.


A variable, or an expression, of primitive type can be automatically converted to a reference type using an
instance of the wrapper class corresponding to that primitive typesuch as an int value becoming an
Integer object. Conversely, a reference to a wrapper object can be converted to the primitive value that is
being wrapped. These primitivetowrapper conversions (termed boxing conversions) are discussed in Chapter



  1. The existence of the boxing conversions means that a variable of type Object can be assigned the value of
    any expression that you can form in the Java programming language.


The type compatibility of an expression in a given context (assignment, argument-passing, operand, etc.) is
affected by different type conversions that can be applied manually or automatically, depending on that
context. Widening and boxing conversions are examples of type conversions that will be automatically
applied in some contexts. The different type conversions that exist and the contexts in which they are applied
are discussed in "Type Conversions" on page 216. If an expression requires multiple conversions, or if there is
no applicable automatic conversion (as in the case of a narrowing conversion), then you must tell the compiler
what conversion to apply by using the cast operator.


3.4.2. Explicit Type Casting


A cast is used to tell the compiler that an expression should be treated as having the type specified by the
castand when applied to primitive types can also affect the value of the expression. A cast consists of a type
name within parentheses, applied to an expression. In the previous example we used a widening cast in
printName to convert the type of this to its superclass type:


Base sref = (Base) this;


This cast was unnecessary but emphasized that we really wanted the current object to be treated as an instance
of its superclass. If we then try to assign sref back to a reference of the narrower More type, an explicit cast
is essential:


More mref = (More) sref;


Even though we know the object referred to is of the right type, the compiler still requires an explicit cast.


A widening conversion is also known as an upcast because it casts from one type to another further up the
type hierarchyit is also a safe cast because it is always valid. A narrowing conversion is also known as a
downcast because it casts from one type to another, further down the inheritance hierarchyit is also an unsafe
cast because it may not be valid.


When a cast is used to request a conversion, the compiler does not assume that the conversion is correct. If the
compiler can tell that is cast is correct, then it can apply the cast. If the compiler can tell that a cast is incorrect
then a compile time error can occur. If the compiler cannot ascertain that the cast is correct at compile time,
then a run time check will be performed. If the run time check fails because the cast is incorrect, then a
ClassCastException is thrown.

Free download pdf