Casting with Reference Types

     

This is very similar to casting with primitives. But it's different. And there are some rules, young lady. Deviation will not be tolerated.

Simple Casting

A reference of any object can be cast to a reference of type java.lang.Object.

You can cast up the class hierarchy, and down the class hierarchy. But you can't cast laterally. This means that a reference to any object O can be cast to a class reference that is a subclass of O if, when it was created, O was a subclass of that class.

You can cast up the class hierarchy automatically ”that is without using the cast operator.

 

 Object o = "some string"; 

Object is up the hierarchy because String extends Object. String is down the class hierarchy from Object. If you cast down the class hierarchy, you must use the cast operator.

 

 Type t = (Type) (someObject); 

A cast could compile and yet still fail at runtime if the cast turns out not to be legal. With the new generics facility in Java 5.0, some of this problem should be alleviated. (See the topic on Generics in More Java Garage .) If it turns out that a compiled class cannot cast at runtime as it hoped it could, a ClassCastException is thrown.

Subclass Casting

Let's say we have the following class hierarchy:

 

 class A {} class B extends A {} class B1 extends A {} class C extends B {} 

Those definitions are legal, and you can type that into a source file. As long as one of them is public, and its name matches the source file name , it will compile. Here's what we can do:

 

 A a = new B();//okB is subclass of A! B b = a; //Error!! can't go up the          //hierarchy w/o casting B b = (B) a; //could possibly fail at runtime b = (B1) b; //nopelateral cast not allowed A a1 = new C(); //okC is indirect subclass of A! C c = new A(); //noC is "narrower" than A C c1 = (C) (new A()); //compiles and fails at runtime 

Interface Casting

A reference to any object O can be cast to an interface reference if one of three things is true.

  1. If O's class implements that interface

  2. If O is a subinterface of that interface

  3. If O is an array type and the interface is the interface Cloneable or Serializable

Let's say we have these classes and interfaces:

 

 class A {} class B extends A implements IInterface {} class B1 extends B implements ISubInterface{} class C extends B1 {} interface IInterface {} interface ISubInterface extends IInterface {} 

Here's a class showing what we can do.

IntCast.java
 

 public class IntCast { public static void main(String[] args) { IInterface b = new B(); //ok, B implements IInterface //b = (B) new A(); //compiles, but fails at runtime //since A doesn't implement IInterface IInterface b1 = new B1(); //works greatB1 implements a subinterface //of IInterface //C c = new IInterface(); //NO! you can't instantiate an interface //they're all abstract! A a = new C(); //that's just fine. System.out.println(a.getClass()); //prints C } } 

Perhaps the most common version of using the interface reference type is with the Collection interface.

 

 Collection c = new ArrayList(); 

Because the ArrayList class implements the Collection interface, you can do this. Then, you can make your methods accept Collection types; if later you decide you want to implement your shopping cart or whatever you're using the ArrayList for as a different kind of list, you can do that without breaking any contracts with clients of the method.

 

 public void doIt(Collection c) { //Now I can use an ArrayList here or a Stack or a //LinkedList or... } 

Array Casting

You can cast an array, but the data they hold must be of compatible types. For example, this code will not compile:

 

 double arr1[] = {1.5,3.14}; int   arr2[] = (int) arr1;   // compile-error 

But arrays holding compatible types can be reassigned to a different reference type. This is all legal:

 

 int[] i = {1,2,3}; int[] j = {3,4}; i = j; java.io.Serializable s = i; java.lang.Cloneable c = j; 

Arrays cannot be converted to any class other than Object or String .

Arrays can be converted to interfaces only of type java.io.Serializable and Cloneable.

Primitive Widening Conversions

Different than casts, which the programmer must perform explicitly, the widening conversion happens automatically.

Widening conversions happen when one primitive type is promoted to another primitive type of greater capacity. For instance, an int can hold only 32 bits of data. A long , on the other hand, can hold 64 bits of data. That makes the following code legal:

 

 int i = 10; long lg = 20; lg = i; //ok, lg now = 10 

Likewise, primitive integer types are implicitly converted to floating point types, like this:

 

 int i = 10; float f = i;//ok, i = 10.0 

If you want to squish a big bucket o' bits into a smaller bucket o' bits, you have to cast.

Every type can be converted to String, even parameterized types.

 

 ArrayList<Integer> a = new ArrayList<Integer>(); a.add(9);     //remember that passing any object to println     //automatically calls its toString() method System.out.println(a); //prints [9] 

Note that in general, these conversion rules can be extended for parameterized types as well. The following, as you might guess, is illegal:

 

 ArrayList<Integer> a = new ArrayList<Integer>(); a.add(67L);//No! looking for int, found long 

Reference Conversions

You can convert from any class, interface, or array (arrays are objects) to an Object reference, or to null .

You can convert from any class to any interface that it implements.

You can convert from any interface to any of its superinterfaces.

For more info on array casting, see the Arrays chapter.

Narrowing Conversions

Narrowing conversions cause you to lose information about the primitive being converted. You can lose precision and magnitude data. So, the compiler requires that you explicitly cast in order to do this.

 

 int i = 10; float f = i; i = f;//illegal without explicit cast 

When you perform a narrowing conversion, you lose all but the lowest order bits.

You cannot convert any primitive type to null . The compiler complains of "incompatible types" if you try to do this.

You cannot convert boolean types to any other types.

I know I already said that. I don't mean to be a nag or anything. It's just, you know, maybe you're reading out of order, or didn't think that was the most fascinating thing you ever heard and needed a little reminder.

Wrapper Conversions

Any primitive to any reference is disallowed except for the following.

Primitive to String is always okay.

Primitive conversion to its corresponding wrapper class is okay, due to autoboxing, and a wrapper class to its corresponding primitive is okay (due to auto-unboxing). The following will not work:

 

 Float f2 = 10;//No! 10 is an int Long g = 20;//No, even though int is smaller than             //long, this is the Long wrapper class 

The int is the default integer type. The following doesn't work either:

 

 Float f2 = 10.99;//No! 10.99 is a double 

The double is the default floating point type. Both of the following work:

 

 Float f2 = 10.99f; Float f3 = 10.99F; 

Cool.



Java Garage
Java Garage
ISBN: 0321246233
EAN: 2147483647
Year: 2006
Pages: 228
Authors: Eben Hewitt

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net