2008-12-30 12 views
5

todo ¡Hola,casting "dinámico" en Java

Se pregunta si hay algún hackers Java ¿Quién me puede pista en por qué no funciona el siguiente:

public class Parent { 
    public Parent copy() { 
     Parent aCopy = new Parent(); 
     ... 
     return aCopy; 
    } 
} 

public class ChildN extends Parent { 
    ... 
} 

public class Driver { 
    public static void main(String[] args) { 
     ChildN orig = new ChildN(); 
     ... 
     ChildN copy = orig.getClass().cast(orig.copy()); 
    } 
} 

el código es muy feliz para compilar, pero decide lanzar una ClassCastException en el tiempo de ejecución D =

Edit: Whoah, realmente respuestas rápidas. ¡Gracias chicos! Entonces parece que no puedo abatir usando este método ... ¿hay alguna otra forma de hacer downcasting en Java? Pensé en hacer que cada clase ChildN sobrescribiera copy(), pero no me entusiasmó agregar el código repetitivo adicional.

+0

Puedes hacerlo. Eche un vistazo a mi edición. Pensé que tenías problemas para entender "casting" en primer lugar. – OscarRyz

Respuesta

1

(No se puede agregar el código en un comentario, así que lo agregaré aquí)

Referente a la clonación: si está implementando Cloneable, impleméntelo de la siguiente manera; mucho más limpio que llamar ...

public class Foo implements Cloneable { 
    public Foo clone() { 
     try { 
      return (Foo) super.clone(); 
     } catch (CloneNotSupportedException e) { 
      return null; // can never happen! 
    } 
} 

[EDIT:. También he visto otras personas utilizan

throw new AssertionError("This should never happen! I'm Cloneable!"); 

en el bloque catch]

+0

¡De hecho, así es como terminé haciéndolo! Aunque mi comentario fue más parecido a // JAVA EPIC FAIL :) – user50264

6

El elenco está tratando de manera efectiva de hacer esto:

ChildN copy = (ChildN) orig.copy(); 

(que está funcionando el reparto de realizar en tiempo de ejecución, pero eso es lo que va a ser porque orig.getClass() habrá ChildN.class) Sin embargo, orig.copy() no lo hace devuelve una instancia de ChildN, devuelve una instancia de solo Parent, por lo que no se puede convertir a ChildN.

4

Si ChildN no anula copia() para devolver una instancia de ChildN, entonces usted está intentando abatido un objeto de tipo matriz para escribir ChildN

9

es como tratar de hacer esto:

public Object copy(){ 
     return new Object(); 
    } 

y luego tratar de:

String s = (String) copy(); 

Su Padre clase y ChildN clase tienen la misma relación que objeto y cadena

Para que funcione lo que tendría que hacer lo siguiente:

public class ChildN extends Parent { 
    public Parent copy() { 
     return new ChildN(); 
    } 
} 

Es decir, anular el método de "copiar" y devolver la derecha ejemplo.


EDITAR

Según su edición. Eso es realmente posible. Esto podría ser una forma posible:

public class Parent { 
    public Parent copy() { 
     Parent copy = this.getClass().newInstance(); 
     //... 
     return copy; 
    } 
} 

De esa manera usted no tiene que anular el método de "copia" en cada subclase. Este es el patrón de diseño del Prototipo.

Sin embargo, con esta implementación debe tener en cuenta dos excepciones marcadas. Aquí está el programa completo que compila y ejecuta sin problemas.

public class Parent { 
    public Parent copy() throws InstantiationException, IllegalAccessException { 
     Parent copy = this.getClass().newInstance(); 
     //... 
     return copy; 
    } 
} 
class ChildN extends Parent {} 

class Driver { 
    public static void main(String[] args) throws InstantiationException , IllegalAccessException { 
     ChildN orig = new ChildN(); 
     ChildN copy = orig.getClass().cast(orig.copy()); 
     System.out.println("Greetings from : " + copy); 
    } 
} 
+0

¡Enseñe con el ejemplo! Esta respuesta es muy clara para mí. Ahora, ¿se puede declarar Child.copy para devolver un ChildN iso a Parent? (Sé que en C++ puede) – xtofl

+0

No en Java. Al menos no en el código fuente de Java. Para confundir el problema levemente, * está * permitido en el código de bytes de Java ... –

+1

Está permitido en el código fuente en Java 5+. –

2

java.lang.Class # fundido (Objeto) lanza un ClassCastException si Clase # isInstance() devuelve falso.Desde el javadoc para ese método:

Determina si el objeto especificado es compatible con asignación con el objeto representado por esta clase. Este método es el equivalente dinámico de la lengua operador instanceof de Java ... En concreto, si esta Class objeto representa una clase declarada , este método devuelve true si el especificado Object argumento es un instancia de la clase representada (o de cualquiera de sus subclases); devuelve false de lo contrario.

Dado que Parent no es una subclase de hijo, isInstance() devuelve falso, por lo que cast() arroja la excepción. Esto puede violar el principio de menos asombro, pero está funcionando de la manera en que está documentado: cast() solo puede subir, no bajar.

2

Podría ser que simplemente desea una copia/clon de su objeto.

En ese caso, implemente la interfaz Cloneable y anule clone() según sea necesario.

public class Parent implement Cloneable { 
    public Object clone() throws CloneNotSupportedException { 
    Parent aCopy = (Parent) super.clone(); 
    ... 
    return aCopy; 
    } 
} 

public class ChildN extends Parent { 
    ... 
} 

public class Driver { 
    public static void main(String[] args) { 
     ChildN orig = new ChildN(); 
     ... 
     ChildN copy = orig.getClass().cast(orig.clone()); 
    } 
} 

Esto hace exactamente lo que su método "copy()" intentó hacer de la manera Java.

(Sí, se puede hacer juegos de introspección de lujo también, pero esos métodos fallar o fea, tan pronto como usted no tiene un valor predeterminado constructor público. Clon funciona en cualquier caso, no importa lo que los constructores que tiene.)

+0

¡También funciona! Escuché que clone() tiene mala reputación, pero no estoy seguro de las razones exactas. – user50264

+0

Esta podría ser la "otra" forma posible. No es necesario cambiar la firma del método (utilizando clonar y devolver el objeto) copiar como nombre y Parent como debe hacer la devolución. – OscarRyz

0

La razón de trabajo downcasting doesnt se debe a que, cuando convierte un objeto primario en un tipo secundario, no hay manera de que pueda invocar los métodos del tipo hijo en el objeto primario. Pero funciona de la otra manera ...