2011-02-01 15 views
96
public class Animal { 
    public void eat() {} 
} 

public class Dog extends Animal { 
    public void eat() {} 

    public void main(String[] args) { 
     Animal animal = new Animal(); 
     Dog dog = (Dog) animal; 
    } 
} 

La asignación Dog dog = (Dog) animal; no genera un error de compilación, pero en tiempo de ejecución se genera un ClassCastException. ¿Por qué el compilador no puede detectar este error?conversión explícita de la superclase a la subclase

+41

USTED le está diciendo al compilador que NO detecte el error. – Mauricio

Respuesta

222

Al usar un elenco básicamente le estás diciendo al compilador "créeme. Soy un profesional, sé lo que estoy haciendo y sé que aunque no puedes garantizarlo, te digo que esta variable animal definitivamente va a ser un perro ".

Dado que el animal no es realmente un perro (es un animal, podría hacer Animal animal = new Dog(); y sería un perro), la VM arroja una excepción en el tiempo de ejecución porque ha violado esa confianza (le dijo al compilador todo estaría bien y no lo es!)

El compilador es un poco más inteligente que aceptar ciegamente todo, si intentas lanzar objetos en diferentes jerarquías de herencia (por ejemplo, lanzar un Perro a una Cadena) el compilador lo lanzará de vuelta a ti porque sabe que nunca podría funcionar.

Debido a que está esencialmente sólo detener el compilador de quejarse, cada vez que lanzas es importante comprobar que no causará un ClassCastException utilizando instanceof en una sentencia if (o algo por el estilo.)

+0

Gracias, pero necesita ampliar el perro de Animal si no, no funciona :) – delive

+14

Me encanta lo dramático que lo hizo sonar –

+1

@delive Por supuesto que sí, pero según la pregunta, 'Dog' * does * extiende de' Animal'! – berry120

38

Debido a que teóricamente Animal animal puede ser un perro:

Animal animal = new Dog(); 

En general, downcasting no es una buena idea. Debes evitarlo. Si lo usa, que incluyen una mejor un cheque:

if (animal instanceof Dog) { 
    Dog dog = (Dog) animal; 
} 
+0

pero el siguiente código genera error de compilación Perro perro = animal nuevo(); (tipos incompatibles) .pero en esta situación el compilador identifica Animal es una súper clase y Dog es una subclase.so que la asignación es incorrecta.pero cuando lanzamos Dog dog = (Dog) animal; acepta. Por favor, explícame sobre esto – saravanan

+3

sí, porque Animal es superclase. No todos los animales son un perro, ¿verdad? Puede referirse a las clases solo por sus tipos o sus supertipos. No sus subtipos – Bozho

+1

por lo que el compilador nos confía solo en el casting..es correcto – saravanan

1

El código genera un error de compilación porque su instancia de tipo es un animal:

Animal animal=new Animal(); 

downcasting no está permitido en Java por varias razones . Ver here para más detalles.

+5

No hay error de compilación, ese es el motivo de su pregunta –

30

con el fin de evitar este tipo de ClassCastException, si tiene:

class A 
class B extends A 

puede definir un constructor en B que toma un objeto de A. de esta manera podemos hacer el "fundido", por ejemplo:

public B(A a) { 
    super(a.arg1, a.arg2); //arg1 and arg2 must be, at least, protected in class A 
    // If B class has more attributes, then you would initilize them here 
} 
17

Dog d = (Dog)Animal; //Compiles but fails at runtime

Aquí están diciendo al compilador "Confía en mí. Sé d que realmente está refiriendo a un objeto Dog", aunque no lo es. Recuerde compilador se ve obligado a confiar en nosotros cuando hacemos un abatido.

El compilador sólo conoce el tipo de referencia declarado. La JVM en el tiempo de ejecución sabe qué es realmente el objeto.

Así que cuando la JVM en el tiempo de ejecución se da cuenta de que el Dog d se refiere en realidad a una Animal y no un objeto Dog que dice. Oye ... le mentiste al compilador y arroja un gran gordo ClassCastException.

Por lo tanto, si está realizando un downcasting, debe utilizar la prueba instanceof para evitar atornillar.

Ahora una pregunta viene a nuestra mente. ¿Por qué demonios el compilador está permitiendo el downcast cuando eventualmente lanzará un java.lang.ClassCastException?

La respuesta es que todo el compilador puede hacer es verificar que los dos tipos están en el mismo árbol de herencia, así que dependiendo de lo que sea de código podría haber llegado antes los abatidos, es posible que animal es de tipo dog.

El compilador debe permitir todo lo que pueda funcionar en el tiempo de ejecución.

considere el siguiente código snipet:

public static void main(String[] args) 
{ 
    Dog d = getMeAnAnimal();// ERROR: Type mismatch: cannot convert Animal to Dog 
    Dog d = (Dog)getMeAnAnimal(); // Downcast works fine. No ClassCastException :) 
    d.eat(); 

} 

private static Animal getMeAnAnimal() 
{ 
    Animal animal = new Dog(); 
    return animal; 
} 

Sin embargo, si el compilador está seguro de que el reparto sería posible sin el trabajo, compilación fallará. ES DECIR. Si intenta convertir los objetos en diferentes herencia jerarquías

String s = (String)d; // ERROR : cannot cast for Dog to String

A diferencia downcasting, upcasting funciona de manera implícita, porque cuando se upcast está restringiendo implícitamente el número de método que se puede invocar, como opuesta a downcasting, que implica que más adelante, es posible que desee invocar un método más específico.

Dog d = new Dog(); Animal animal1 = d; // Works fine with no explicit cast Animal animal2 = (Animal) d; // Works fine with n explicit cast

Tanto la conversión hacia arriba anterior funcionará bien sin ninguna excepción, porque un perro es-A animal, anithing un animal puede hacer, un perro puede hacer. Pero no es verdad vica-versa.

1

Como se explicó, no es posible. Si desea usar un método de la subclase, evalúe la posibilidad de agregar el método a la superclase (puede estar vacío) y llame desde las subclases obteniendo el comportamiento que desea (subclase) gracias al polimorfismo. Así que cuando llame a d.method() la llamada tendrá éxito sin moldear, pero en caso de que el objeto no sea un perro, no habrá un problema

Cuestiones relacionadas