Domanda

Ho scritto questo metodo clone per quando il genitore della classe Employee è astratto e il metodo clone () nella classe parent è astratto. Volevo copiare il tipo di dati primitivo dell'oggetto Employee con questo codice invece di copiare ogni tipo di dati primitivo individualmente, ma questo codice ha problemi con la linea che chiamo metodo clone (). (Questo codice è nella classe Employee)

public Object clone() {
    Object obj = new Object();
    Object object = obj.clone();  //Emphasis here
    return object;

}

l'errore è: il metodo clone () dal tipo Object non è visibile.

Ma la mia classe Employee è nella gerarchia di classi che può accedere al metodo clone () protetto nella classe Object.

Questa è la mia semplice classe Employee:

public class Employee extends Person implements Cloneable {
private int ID;

public Employee() {
    ID = 0;
}

public void setID(int ID) {
    this.ID = ID;
}

public int getID() {
    return ID;
}

public Object clone1() throws CloneNotSupportedException {
    try {
        Object obj = new Object();

        Object object = obj.clone();
        return object;
    } catch (CloneNotSupportedException ex) {
        return null;
    }
}
È stato utile?

Soluzione

Hai implementato l'interfaccia Cloneable sul tuo oggetto?

Tuttavia, ci sono pochissimi casi in cui userei il clone per copiare un oggetto. Un esempio sicuro è array.clone (). Preferirei usare il linguaggio del costruttore di copie o copiare / assegnare manualmente i valori in giro.

Esiste l'articolo n. 11 in Java efficace (2a edizione) sull'argomento problema di fondo. L'interfaccia clonabile è un tipo speciale di interfaccia in quanto modifica il comportamento della classe Object rispetto alla clonazione. Fondamentalmente si tratta di una funzione che abilita l'interfaccia class in Java.

Modifica: in base al tuo esempio potresti dover racchiudere la chiamata clone () in un tentativo di cattura di CloneNotSupportedException in un caso generale.

Modifica2: ho riformulato la mia risposta

Modifica3: Hai ignorato il clone () nel contesto public? Nell'esempio che hai fornito, prova a clonare un oggetto, che si trova nel pacchetto java.lang, quasi il pacchetto in cui si trova il tuo codice.

Edit4: Penso che la risposta sia già negli altri post, volevo solo riflettere sul problema di fondo.

Modifica5: Prova questo:

public Object clone1() throws CloneNotSupportedException {        
    return super.clone();        
}

Modifica6 Quindi dai un nome al tuo metodo public abstract Object copy() per esempio e nell'implementazione, usa super.clone () - per evitare confusione.

Modifica7 Ho fatto qualche eclissi e sono uscito con la seguente soluzione:

public class Cloner {
    public static abstract class Person {
       protected abstract Object clone1() throws CloneNotSupportedException;
       public Object copy() throws CloneNotSupportedException {
           return clone1();
       }
    }
    public static class Employee extends Person implements Cloneable {
        @Override
        protected Object clone1() throws CloneNotSupportedException {
            return super.clone();
        }

    }
    public static void main(String[] args) throws Exception {
        new Employee().copy();
    }
}

Ma sostanzialmente è lo stesso concetto di rinominare il tuo metodo astratto con qualcos'altro che clone ().

Modifica8: risolto il mio esempio, ora funziona senza eccezioni.

(Ma il credito effettivo va a G & # 225; bor Hargitai per super.clone())

Altri suggerimenti

Il modello standard per rendere clonabile una classe è:

  1. Implementa Cloneable
  2. Sostituisci il metodo clone() e rendilo pubblico
  3. In super.clone() chiama new, quindi copia lo stato di qualsiasi oggetto mutabile

Dovresti non creare un nuovo oggetto usando Object. Il modo corretto è chiamare <=> per una nuova istanza. <=> di <=> è speciale e creerà una nuova copia dell'oggetto e ne copierà i campi e i riferimenti primitivi.

Ad esempio:

public class Person implements Cloneable {
    protected String name;
    // Note that overridden clone is public
    public Object clone() {
        Person clone = (Person)super.clone();
        // No need to copy name as the reference will be
        // copied by Object's clone and String is immutable
        return clone;
    }
}

public class Employee extends Person {
    protected int id;
    protected java.awt.Point location;
    public Object clone() {
        Employee  clone = (Employee )super.clone();
        // No need to copy id as Object's clone has already copied it
        // Need to clone location as Point is mutable and could change
        clone.location = location.clone();
        return clone;
    }
}

Il meccanismo di clonazione di Java è alquanto imbarazzante. Per poter clonare se stesso, la classe deve fare due cose. Innanzitutto deve implementare Clonable. In secondo luogo deve sovrascrivere clone () e renderlo pubblico.

Nel tuo esempio, hai ignorato clone () ma stai invocando clone () non sulla classe Employee ma piuttosto su Object.class () dove clone () è protetto solo.

Penso che l'attuale risposta verde sia negativa , perché potresti chiedere?

  • Aggiunge molto codice
  • Richiede di elencare tutti i campi da copiare e farlo
  • Questo non funzionerà per gli elenchi quando si usa clone () (Questo è ciò che dice clone () per HashMap: restituisce una copia superficiale di questa istanza di HashMap: le chiavi e il valore stesso non sono clonati.) Quindi finisci per farlo manualmente (questo mi fa piangere)

Oh, e tra l'altro anche la serializzazione è male, potresti dover aggiungere Serializable ovunque (anche questo mi fa piangere).

Quindi qual è la soluzione:

Libreria Java di deep-cloning La libreria di clonazione è una piccola libreria java open source (licenza apache) che esegue la clonazione di oggetti. Gli oggetti non devono implementare l'interfaccia Cloneable. In effetti, questa libreria può clonare QUALSIASI oggetto Java. Può essere utilizzato, ad esempio, nelle implementazioni della cache se non si desidera modificare l'oggetto memorizzato nella cache o quando si desidera creare una copia profonda degli oggetti.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Dai un'occhiata a http://code.google.com/p/cloning/

Mister Bloch di Effective Java ha alcune parole interessanti da dire sull'uso di clone.

http://www.artima.com/intv/bloch13.html

Generalmente il pensiero attuale è quello di evitare l'uso del clone in quanto soggetto a errori e ampiamente frainteso, implementare il costruttore di copie è una strategia alternativa o usare un approccio a forza bruta per copiare in profondità l'oggetto usando la serializzazione.

Dovresti semplicemente scrivere

return super.clone(); 

nel tuo metodo clone e implementa l'interfaccia Clonable.

Hai implementato l'interfaccia appropriata? Potrebbe essere così semplice, anche se potresti aver già tenuto conto di questo.

Vedi qui per maggiori informazioni: http://java.sun.com/javase/6/docs/api/java/lang/Object.html#clone ()

Non ho molta familiarità con Java ma questo può aiutare: http://en.wikipedia.org/wiki/Clone_(Java_method)

Un estratto dal post:

  

Un altro svantaggio è quello spesso   impossibile accedere al metodo clone () su un   tipo astratto. La maggior parte delle interfacce e   le classi astratte in Java no   specifica un metodo clone pubblico (). Come un   risultato, spesso l'unico modo per utilizzare il   Il metodo clone () è se conosci il   classe effettiva di un oggetto; che è   contrariamente al principio di astrazione   di usare il tipo più generico   possibile. Ad esempio, se uno ha un   Elenco di riferimento in Java, non è possibile   invoca clone () su quel riferimento   perché Elenco non specifica alcun pubblico   metodo clone (). Implementazioni effettive   di elenco come ArrayList e LinkedList   tutti generalmente hanno metodi clone ()   stessi, ma è scomodo e   cattiva astrazione da portare in giro   tipo di classe effettivo di un oggetto.

Fondamentalmente per avere un oggetto correttamente clonabile è sufficiente avere un metodo clone () pubblico implementato in quella classe.

L'interfaccia clonabile è un'interfaccia marker utilizzata per segnalare alla VM che è sicuro implementare il metodo clone () protetto predefinito come copia campo per campo.

Per implementare correttamente il metodo clone per una classe dovresti dichiarare un clone di metodo pubblico come questo ().

public Object clone() {
   return super.clone();
}

Una buona implementazione funzionante creerà un nuovo oggetto e assegnerà correttamente i campi quando la logica aziendale lo richiede:

public Object clone() {
   CurrentClass newObject = new CurrentClass();

   newObject.field1 = this.field1; // for simple types: int, long, etc
   newObject.referenceField = this.referenceField.clone(); // for agregate objects or references.
   return newObject;
}

La conclusione:  dichiarare un metodo di clonazione pubblico.  Se si desidera avere l'implementazione predefinita come campo per campo, copiare la chiamata super e contrassegnare la classe come Cloneable  Se desideri solo la clonazione personalizzata, puoi ignorare il segno Cloneable.

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