Downcasting em Java

O upcasting é permitido em Java, no entanto, o downcasting gera um erro de compilation.

O erro de compilation pode ser removido adicionando-se um casting mas, de qualquer forma, seria interrompido no tempo de execução.

Nesse caso, por que o Java permite downcasting se não puder ser executado no tempo de execução?
Existe algum uso prático para este conceito?

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"); } } 

O downcasting é permitido quando existe a possibilidade de que ele seja bem-sucedido no tempo de execução:

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

Em alguns casos, isso não será bem-sucedido:

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

Em outros, funcionará:

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

Note que alguns lançamentos não serão permitidos em tempo de compilation, porque eles nunca serão bem-sucedidos:

 Integer i = getSomeInteger(); String s = (String) i; // the compiler will not allow this, since i can never reference a String. 

Usando seu exemplo, você poderia fazer:

 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(); } 

Eu acredito que isso se aplica a todas as linguagens estaticamente tipadas:

 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 

O typecast efetivamente diz: assuma que esta é uma referência à class do casting e use-a como tal. Agora, vamos dizer o é realmente um Integer, supondo que isso é uma String não faz sentido e dará resultados inesperados, portanto, deve haver uma verificação de tempo de execução e uma exceção para notificar o ambiente de tempo de execução que algo está errado.

No uso prático, você pode escrever código trabalhando em uma class mais geral, mas convertê-lo em uma subclass se você souber qual subclass é e precisar tratá-la como tal. Um exemplo típico está substituindo Object.equals (). Suponha que temos uma aula para o carro:

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

Todos nós podemos ver que o código que você forneceu não funcionará em tempo de execução. Isso porque sabemos que a expressão new A() nunca pode ser um object do tipo B

Mas não é assim que o compilador vê isso. No momento em que o compilador está verificando se a conversão é permitida, apenas vê isto:

 variable_of_type_B = (B)expression_of_type_A; 

E como outros demonstraram, esse tipo de casting é perfeitamente legal. A expressão à direita poderia muito bem avaliar um object do tipo B O compilador vê que A e B têm uma relação de subtipo, portanto, com a visualização “expression” do código, a conversão pode funcionar.

O compilador não considera o caso especial quando ele sabe exatamente qual tipo de object a expression_of_type_A realmente terá. Ele apenas vê o tipo estático como A e considera que o tipo dynamic pode ser A ou qualquer descendente de A , incluindo B

Nesse caso, por que o Java permite downcasting se não puder ser executado no tempo de execução?

Eu acredito que isso é porque não há como o compilador saber em tempo de compilation se o casting terá sucesso ou não. Para o seu exemplo, é simples ver que o casting falhará, mas há outras ocasiões em que não é tão claro.

Por exemplo, imagine que os tipos B, C e D estendam o tipo A e, em seguida, um método public A getSomeA() retorna uma instância de B, C ou D, dependendo de um número gerado aleatoriamente. O compilador não pode saber qual tipo exato de tempo de execução será retornado por esse método, portanto, se você converter os resultados posteriormente em B , não há como saber se o lançamento será bem-sucedido (ou falhará). Portanto, o compilador deve assumir que os lançamentos serão bem-sucedidos.

@ Original Poster – ver comentários in-line.

 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"); } } 

Downcast funciona no caso quando estamos lidando com um object upcasted. Upcasting:

 int intValue = 10; Object objValue = (Object) intvalue; 

Então agora essa variável objValue sempre pode ser downcasted para int porque o object que foi convertido é um Integer ,

 int oldIntValue = (Integer) objValue; // can be done 

mas como objValue é um Object, ele não pode ser convertido em String porque int não pode ser convertido em String .

Downcasting é muito útil no trecho de código a seguir eu uso isso o tempo todo. Provando assim que downcasting é útil.

 private static String printAll(LinkedList c) { Object arr[]=c.toArray(); String list_string=""; for(int i=0;i 

Eu armazeno String na linked list. Quando recupero os elementos da Lista vinculada, os objects são retornados. Para acessar os elementos como Strings (ou qualquer outro object de class), o downcasting me ajuda.

O Java nos permite compilar código deprimido confiando em nós que estamos fazendo a coisa errada. Ainda assim, se os humanos cometerem um erro, ele será pego em tempo de execução.

Considere o exemplo abaixo

 public class ClastingDemo { /** * @param args */ public static void main(String[] args) { AOne obj = new Bone(); ((Bone) obj).method2(); } } class AOne { public void method1() { System.out.println("this is superclass"); } } class Bone extends AOne { public void method2() { System.out.println("this is subclass"); } } 

aqui nós criamos o object da subclass Bone e o atribuímos à superclass AOne reference e agora a superclass reference não sabe sobre o método method2 na subclass ie Bone durante o tempo de compilation.Portanto, precisamos fazer downcast desta referência de superclass para subclass reference assim como a referência resultante pode saber sobre a presença de methods na subclass, ou seja, osso

Intereting Posts