Domanda

Salve a tutti,

Mi chiedo se ci sono hacker Java che possono darmi un'idea del perché non funziona:

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

Il codice è abbastanza felice da compilare, ma decide di lanciare ClassCastException in fase di esecuzione D =

Modifica: Whoah, risposte davvero veloci. Grazie ragazzi! Quindi sembra che non sia possibile effettuare il downcast utilizzando questo metodo ... esiste un altro modo per eseguire il downcast in Java? Ho pensato di avere ogni classe ChildN sovrascrivere copy () , ma non ero entusiasta di aggiungere il codice aggiuntivo boilerplate.

È stato utile?

Soluzione

(Impossibile aggiungere il codice in un commento, quindi aggiungerò qui)

Riguardo a Cloneable: se stai implementando Cloneable, implementalo come segue; molto più pulito da chiamare ...

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

[EDIT: ho visto anche altre persone usare

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

nel blocco catch.]

Altri suggerimenti

È come provare a fare questo:

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

E quindi provare a:

  String s = ( String ) copy();

La tua classe Parent e ChildN hanno la stessa relazione di Object e String

Per farlo funzionare dovresti fare quanto segue:

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

Cioè, sovrascrivi la " copia " metodo e restituisce l'istanza corretta.


Modifica

Come da modifica. Questo è effettivamente possibile. Questo potrebbe essere un modo possibile:

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

In questo modo non è necessario ignorare " copia " metodo in ogni sottoclasse. Questo è il modello di progettazione del prototipo.

Comunque usando questa implementazione dovresti essere consapevole di due eccezioni verificate. Ecco il programma completo che viene compilato ed eseguito senza problemi.

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

Il cast sta effettivamente cercando di farlo:

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

(Sta lavorando al cast per esibirsi al momento dell'esecuzione, ma è quello che sarà perché orig.getClass () sarà ChildN.class ) Tuttavia, < code> orig.copy () non restituisce un'istanza di ChildN, restituisce un'istanza di Parent , quindi non può essere trasmessa a ChildN .

Se ChildN non sovrascrive copy () per restituire un'istanza di ChildN, allora si sta tentando di eseguire il downcast di un oggetto di tipo parent per digitare ChildN

java.lang.Class # cast (Object) genera ClassCastException se Class # isInstance () restituisce false. Dal javadoc per quel metodo:

  

Determina se l'oggetto specificato è   assegnazione compatibile con l'oggetto   rappresentato da questa classe. Questo metodo   è l'equivalente dinamico di Java   istanza della lingua dell'operatore ...   In particolare, se questo   L'oggetto Class rappresenta a   classe dichiarata, questo metodo restituisce    true se specificato   L'argomento Object è un   istanza della classe rappresentata (o   di una delle sue sottoclassi); ritorna    false altrimenti.

Poiché Parent non è una sottoclasse di child, isInstance () restituisce false, quindi cast () genera l'eccezione. Questo può violare il principio del minimo stupore, ma funziona nel modo in cui è documentato: cast () può solo eseguire l'upgrade, non il downcast.

Potrebbe essere che tu voglia semplicemente una copia / clone del tuo oggetto.

In tal caso, implementare l'interfaccia Cloneable e sovrascrivere clone () se necessario.

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

Questo fa esattamente ciò che " copy () " metodo ha provato a fare in modo Java.

(Sì, potresti anche fare fantasiosi giochi di introspezione, ma quei metodi falliscono o diventano brutti non appena non hai un costruttore predefinito pubblico. Il clone funziona in ogni caso, indipendentemente dai costruttori che hai.)

Il motivo del downcasting non funziona perché, quando si esegue il cast di un oggetto parent su un tipo child, non è possibile invocare i metodi del tipo child sull'oggetto parent. Ma funziona nell'altro modo ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top