Domanda

C'era una volta una classe:

public class Scope<C extends Cloneable & Comparable<C>> implements Comparable<Scope<C>>, Cloneable, Serializable {

   private C starts;
   private C ends;
   ...

   @SuppressWarnings("unchecked")
   @Override
   public Object clone() {
       Scope<C> scope;
       try {
           scope = (Scope<C>) super.clone();
           scope.setStarts((C) starts.clone()); // The method clone() from the type Object is not visible
           scope.setEnds((C) ends.clone()); // The method clone() from the type Object is not visible
       } catch (CloneNotSupportedException e) {
           throw new RuntimeException("Clone not supported");
       }
       return scope;
   }
}

In Object abbiamo:

protected native Object clone() throws CloneNotSupportedException;

E l'interfaccia clonabile è:

public interface Cloneable { 
}

Come dovrei clonarlo?

È stato utile?

Soluzione

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/

Altri suggerimenti

Questo è uno dei motivi per cui a nessuno piace Cloneable . Dovrebbe essere un'interfaccia marcatore, ma è sostanzialmente inutile perché non puoi clonare un oggetto Cloneable arbitrario senza riflessione.

Praticamente l'unico modo per farlo è creare la tua interfaccia con un metodo pubblico clone () (non deve essere chiamato " < code> clone () "). Ecco un esempio da un'altra domanda StackOverflow.

Spero di aver risolto il problema della clonazione generica in Java:

public class Generic<T> {
  private T data;

  public Generic() {
    // ...
  }

  @SuppressWarnings("unchecked")
  @Override
  public Object clone() {
    Generic<T> cloned = new Generic<T>();
    try {
      cloned.data = (T) data.getClass().getMethod("clone").invoke(data);
    } catch (Exception e) {
      // ...
    }
    return cloned;
  }
}

Leggermente OT, ma potresti risparmiarti un sacco di dolori futuri con questo:

   catch (CloneNotSupportedException e) {
       throw new RuntimeException("Clone not supported", e);
   }

In modo che quando ottieni una traccia dello stack sai quale oggetto ha causato il problema.

Per rispondere alla domanda principale, la tua interfaccia che implementa un clone pubblico () come ha scritto mmyers e richiede che anche C lo estenda.

Come commento generale, evitare di usare Object.clone () ogni volta che è possibile. Se hai il controllo del codice in questione, implementa invece un costruttore di copie. Vedi qui per informazioni.

Come vedi, se una classe tenta di implementare Cloneable e vuoi un clone deep , allora tutti i tuoi oggetti costituenti devono essere immutabili, primitivi o necessari essere anche clonabile.

Spesso, un approccio migliore e più semplice è quello di creare un costruttore di copie.

public class Scope<C extends Comparable<C>> implements Comparable<Scope<C>>, Serializable {
    private C starts;
    private C ends;
    public Scope(final Scope original) {
       starts = new C(original.starts);
       ends = new C(original.ends);
       // initialize all my other fields from "original"
    }
}

e ovviamente hai bisogno di un costruttore di copie su C in grado di gestire il polimorfismo.

Se non si ha accesso o possibilità di modificare l'origine in C , qualsiasi metodo di copia, indipendentemente dal metodo, sarà molto difficile e potenzialmente impossibile. Ad esempio, non è possibile creare una copia di un'istanza enum .

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