tags:

views:

4893

answers:

6

Upcasting is allowed in Java, however downcasting gives a compile error.

The compile error can be removed by adding a cast but would anyway break at the runtime.

In this case why Java allows downcasting if it cannot be executed at the runtime?
Is there any practical use for this concept?

public class demo {
  public static void main(String a[]) {
      B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException
  }
}

class A {
  public void draw() {
    System.out.println("1");
  }

  public void draw1() {
    System.out.println("2");
  }
}

class B extends A {
  public void draw() {
    System.out.println("3");
  }
  public void draw2() {
    System.out.println("4");
  }
}
+17  A: 

Downcasting is allowed when there is a possibility that it suceeds at run time:

Object o = getSomeObject(),
String s = (String) o; // this is allowed because o could reference a String

In some cases this will not succeed:

Object o = new Object();
String s = (String) o; // this will fail at runtime, because o doesn't reference a String

In others it will work:

Object o = "a String";
String s = (String) o; // this will work, since o references a String

Note that some casts will be disallowed at compile time, because they will never succeed at all:

Integer i = getSomeInteger();
String s = (String) i; // the compiler will not allow this, since i can never reference a String.
Joachim Sauer
Thanks for the typo-fix, Epaga
Joachim Sauer
+3  A: 

I believe this applies to all statically typed languages:

String s = "some string";
Object o = s; // ok
String x = o; // gives compile-time error, o is not neccessarily a string
String x = (String)o; // ok compile-time, but might give a runtime exception if o is not infact a String

The typecast effectively says: assume this is a reference to the cast class and use it as such. Now, lets say o is really an Integer, assuming this is a String makes no sense and will give unexpected results, thus there needs to be a runtime check and an exception to notify the runtime environment that something is wrong.

In practical use, you can write code working on a more general class, but cast it to a subclass if you know what subclass it is and need to treat it as such. A typical example is overriding Object.equals(). Assume we have a class for Car:

@Override
boolean equals(Object o) {
    if(!(o instanceof Car)) return false;
    Car other = (Car)o;
    // compare this to other and return
}
Rolf Rander
+2  A: 

Using your example, you could do:

public void doit(A a) {
    if(a instanceof B) {
        // needs to cast to B to access draw2 which isn't present in A
        // note that this is probably not a good OO-design, but that would
        // be out-of-scope for this discussion :)
        ((B)a).draw2();
    }
    a.draw();
}
Rolf Rander
A: 

In this case why Java allows downcasting if it cannot be executed at the runtime?

I believe this is because there is no way for the compiler to know at compile-time if the cast will succeed or not. For your example, it's simple to see that the cast will fail, but there are other times where it is not so clear.

For instance, imagine that types B, C, and D all extend type A, and then a method public A getSomeA() returns an instance of either B, C or D depending on a randomly generated number. The compiler cannot know which exact run-time type will be returned by this method, so if you later cast the results to B, there is no way to know if the cast will succeed (or fail). Therefore the compiler has to assume casts will succeed.

matt b
+1  A: 

We can all see that the code you provided won't work at run time. That's because we know that the expression new A() can never be an object of type B.

But that's not how the compiler sees it. By the time the compiler is checking whether the cast is allowed, it just sees this:

variable_of_type_B = (B)expression_of_type_A;

And as others have demonstrated, that sort of cast is perfectly legal. The expression on the right could very well evaluate to an object of type B. The compiler sees that A and B have a subtype relation, so with the "expression" view of the code, the cast might work.

The compiler does not consider the special case when it knows exactly what object type expression_of_type_A will really have. It just sees the static type as A and considers the dynamic type could be A or any descendant of A, including B.

Rob Kennedy
A: 

@ Original Poster - see inline comments.

public class demo {
public static void main(String a[]) {

B b = (B) new A(); // compiles with the cast, but runtime exception - java.lang.ClassCastException 
//- A subclass variable cannot hold a reference to a superclass  variable. so, the above statement will not work.

  //For downcast, what you need is a superclass ref containing a subclass object.
  A superClassRef = new B();//just for the sake of illustration
  B subClassRef = (B)superClassRef; // Valid downcast. 

}
}

class A {
  public void draw() {
  System.out.println("1");
 }

 public void draw1() {
   System.out.println("2");
 }
}

class B extends A {
  public void draw() {
   System.out.println("3");
  }
  public void draw2() {
   System.out.println("4");
  }
 }

`

Alok Sharma