Pregunta

Hola a todos,

Preguntándome si hay algún pirata informático de Java que pueda darme cuenta de por qué no funciona lo 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 está muy feliz de compilar, pero decide lanzar una ClassCastException en tiempo de ejecución D =

Editar: Whoah, respuestas realmente rápidas. ¡Gracias chicos! Así que parece que no puedo hacer downcast usando este método ... ¿hay alguna otra manera de hacer downcasting en Java? Pensé en tener que cada clase de ChildN sobreescribiera copy () , pero no estaba entusiasmado con la adición del código adicional de la plantilla.

¿Fue útil?

Solución

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

Respecto a Cloneable: si está implementando Cloneable, implementarlo de la siguiente manera; mucho más limpio para llamar ...

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

[EDITAR: También he visto a otras personas usar

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

en el bloque catch.]

Otros consejos

Es como tratar de hacer esto:

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

Y luego intenta:

  String s = ( String ) copy();

Su Parent y la clase ChildN tienen la misma relación que Object y String

Para que funcione, deberías hacer lo siguiente:

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

Es decir, anular la " copia " Método y devolver la instancia correcta.


EDIT

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

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

De esa forma, no tiene que anular la " copia " Método en cada subclase. Este es el patrón de diseño de prototipo.

Sin embargo, al utilizar 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 );
    }
}

El reparto está tratando de hacer esto:

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

(Está resolviendo el reparto para que se ejecute en el momento de la ejecución, pero eso es lo que será porque orig.getClass () será ChildN.class ) Sin embargo, < code> orig.copy () no devuelve una instancia de ChildN, devuelve una instancia de solo Parent , por lo que no se puede convertir a ChildN .

Si ChildN no anula copy () para devolver una instancia de ChildN, entonces está tratando de derribar un objeto de tipo padre para escribir ChildN

java.lang.Class # cast (Object) lanza una ClassCastException si Class # isInstance () devuelve false. Desde el javadoc para ese método:

  

Determina si el objeto especificado es   asignación compatible con el objeto   representado por esta Clase. Este método   Es el equivalente dinámico de Java.   idioma instancia del operador ...   Específicamente, si esto   El objeto Class representa un   clase declarada, este método devuelve    true si el especificado   El argumento Object es un   instancia de la clase representada (o   de cualquiera de sus subclases); vuelve    false de lo contrario.

Dado que Parent no es una subclase de child, isInstance () devuelve false, por lo que cast () lanza la excepción. Esto puede violar el principio de menos asombro, pero está funcionando de la manera en que está documentado: cast () solo puede hacer upcast, no downcast.

Podría ser que simplemente quieras una copia / clonación de tu objeto.

En ese caso, implemente la interfaz Cloneable e invalide 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 tu " copy () " Método intentado hacer en la forma de Java.

(Sí, también podrías hacer juegos de introspección sofisticados, pero esos métodos fallan o se vuelven feos en cuanto no tienes un constructor público predeterminado. La clonación funciona en cualquier caso, independientemente de los constructores que tengas).

La razón por la que no funciona el desembolso descendente es porque, cuando se convierte un objeto primario en un tipo secundario, no hay forma de invocar métodos del tipo secundario en el objeto principal. Pero funciona a la inversa ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top