What are all of the different kinds of type casting in Java and what do they mean?

John Mitchell

Type casting conversions are covered in Section 5.5 of the JLS. See the JLS for all of the gory details.

There are five (5) categories of legal type casting conversions: identity conversion, narrowing and widening primitive conversions, narrowing and widening reference conversions. There's also a category of "forbidden" conversions.

Note that value set conversion is a necessary adjunct to type casting conversions. Value set conversion happens after the type casting conversion dealing with floating point types and is covered in Section 5.1.8 of the JLS.

Note also that there are implicit conversions which are applied in to the expressions in assignments (aka "assignment conversion") and to the actual arguments in method invocations (aka "method invocation conversion"). Assignment conversion is covered in Sections 5.2 and 15.26 of the JLS and method invocation conversion is covered in Sections 5.3, 15.9, and 15.12 of the JLS.

The forbidden conversions... In general, primitive types cannot have their values casted to a reference type and, conversely, reference types cannot have their values casted to a primitive type. The null type cannot be converted to/from any primitive type. Array types may not be converted to each other unless their base types are convertible to each other. Arrays can't be converted to a class type other than Object or String. The boolean type can only be converted to boolean and to String and nothing else can be converted to boolean except itself. For the exhaustive list, see section 5.1.7 of the JLS.

In addition, String casting is simple... You can't do it. Yes, it's true that all types, including null, can be converted to String but you may not cast anything to the String type (with the single exception of the identity conversion). This is covered in Sections 5.1.6 and 5.4 of the JLS.

Identity conversion is also simple. You can convert anything to the same type as itself. I.e., int to int. While this may seem silly, it's an important base case which allows for things like redundant casts.

Primitive types can have their values cast to other primitive types via identity conversion or narrowing or widening primitive conversions. A key point to note is that, by definition, neither narrowing nor widening primitive conversions will generate run-time exceptions.

Narrowing primitive conversion is the conversion of a larger type to a smaller type. I.e., int to byte. Given that the smaller type cannot represent all of the possible values of the larger type, narrowing primitive conversions may lose information. For example, narrowing of integral types is performed by discarding all but the number of lowest order bits which will fit into the target type. See Section 5.1.3 of the JLS for rest of the conversion details.

Widening primitive conversion is the conversion of a smaller primitive type to a larger primtive type. I.e., short to long. Widening of integral types to other integral types and from float to double are precise and lose no numeric value information. Widening conversions from integral types to floating point types may result in a loss of precision due to the nature of floating point representations. See Section 5.1.2 of the JLS for the rest of the details.

Reference types can have their values cast to other reference types via identity conversion or narrowing or widening conversions and a special conversion of the null type to any reference type.

A quick aside on alternative nomenclature... A good number of people use the terms "upcasting" and "downcasting" when talking about type casting references. Their notion of "up" and "down" relate to their view of class hierarchies being drawn with the root class at the top and the subclasses drawn successively lower. [They also call them inheritance trees even though they've drawn the tree upside down. :-)] In that model, "upcasting" is equivalent to a "widening reference conversion" and "downcasting" is equivalent to a "narrowing reference conversion." Due to the potential confusion, I recommend that you refrain from using the "upcasting" and "downcasting" terminology.

A narrowing reference conversion is the conversion of a reference to a given type to a reference of another type which is more restrictive and type compatible. I.e., Number to Integer (since Integer is a sub-class of Number). Similarly, you can cast a super-interface to any of it's sub-interfaces. You can cast Object references to any class, interface, or array type. See Section 5.1.5 of the JLS for comprehensive coverage.

Note very clearly that narrowing reference conversions require a run-time test to make sure that the actual reference object is allowed to be referenced by the narrowed typed reference. If it's not then the run-time system will throw a ClassCastException. You may, of course, use the instanceof operator to check that yourself.

A widening reference conversion is the conversion of a reference to a given type to a reference of another type which is less restrictive and type compatible. I.e., Integer to Number (since Integer is a sub-class of Number). Similarly, you may cast a sub-interface to any of its super-interfaces. Also, you may cast a class to any of the interfaces which it implements. Any class or interface reference to the Object type. Casts are also allowed from null to any class, interface, or array type. For the full list, read Section 5.1.4 of the JLS.

Note that widening reference conversions require only a source compile-time check for correctness and therefore they do not throw any sort of run-time exception.

0 Comments  (click to add your comment)
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

About | Sitemap | Contact