2009-11-26 18 views
6

E 'troppo tardi per cambiare la domanda, ma più precisa sarebbe stata quella di chiedere: "Perché il clone() non consentono single?". Un metodo copy() sarebbe più conveniente.Perché Java enumerazioni non clonabile?


C'è qualche motivo per cui le enumerazioni in Java non possono essere clonati?

Il manuale che

Questo garantisce che le enumerazioni non sono mai clonati, che è necessario per preservare il loro status "Singleton".

Ma restituire l'istanza stessa preserverebbe anche il suo stato e sarei in grado di gestire enumerazioni associate allo stesso modo degli altri oggetti clonabili.

Si potrebbe obiettare che

L'intento generale [del clone()] è che, per qualsiasi oggetto x, l'espressione: x.clone() != x sarà vero, [...]

Ma per single, al contrario, voglio x.clone() == x per essere vero. Se l'istanza stessa fosse restituita, allora il modello singleton sarebbe trasparente agli oggetti di riferimento.

Quindi perché non è possibile clonare le enumerazioni o si è dimenticato di pensare a singleton e immutables, quando è stato specificato clone()?

+0

Con le enumerazioni, cosa c'è da clonare? – omerkudat

risposta

5

Ma per single, al contrario, voglio x.clone() == x per essere vero.

È potrebbe voler, ma penso che sia strano che il seguente codice si spezzasse:

interface Foo extends Cloneable { public int getX(); public void setX(int x); } 
enum FooSingleton implements Foo { 
    INSTANCE; 
    private int x; 
    public int getX(){ return x; } 
    public void setX(int x){ this.x = x; } 
} 
class FooClass implements Foo { 
    private int x; 
    public int getX(){ return x; } 
    public void setX(int x){ this.x = x; } 
} 

boolean omg(Foo f){ 
    Foo c = f.clone(); 
    c.setX(c.getX() + 1); 
    return c.getX() != f.getX(); 
} 
assert omg(new FooClass());  // OK 
assert omg(FooSingleton.INSTANCE); // WTF? 

(Naturalmente, poiché clone() dà solo copie poco profonde, anche una corretta attuazione di esso può causa errori nel codice sopra.)

D'altra parte, posso essere d'accordo sul fatto che avrebbe senso per le operazioni di clonazione a solo return this per gli oggetti immutabili, e le enumerazioni dovrebbero essere immutabili. Ora, quando è stato scritto il contratto per clone(), a quanto pare non pensavano agli immutabili, o non volevano un caso speciale per un concetto che non è supportato dal linguaggio (cioè tipi immutabili).

E così, clone() è quello che è, e non si può andare molto bene e cambiare qualcosa che è stato intorno da Java 1.0. Sono abbastanza sicuro che da qualche parte là fuori, c'è un codice che si basa interamente su clone() restituendo un nuovo oggetto distinto, forse come una chiave per uno IdentityHashMap o qualcosa del genere.

1

immagino che non volevano per il trattamento di single come un caso speciale quando è stato specificato clone(). Ciò avrebbe complicato le specifiche. Così ora gli sviluppatori della libreria devono trattarli come un caso speciale, ma per il resto di noi, è bello che possiamo avere fiducia che x.clone() != x.

6

Se il metodo clone restituisce l'istanza this anziché un oggetto distinto, non è un clone, vero?

The Javadoc dice:

Per convenzione, l'oggetto restituito da questo metodo dovrebbe essere indipendente questo oggetto (che viene clonato).

Le enumerazioni non dovrebbero essere clonate perché si suppone che ci sia sempre un'istanza di ciascun valore.

EDIT: In risposta al seguente commento:

Questo è esattamente quello che critico. Perché non restituire lo stesso esempio, se ci non può essere uno diverso?

Perché non ha molto senso. Se si tratta dello stesso oggetto, allora non è un clone.Il Javadocs anche dire:

L'intento generale è che, per ogni oggetto x, l'espressione:

x.clone() != x
sarà vero, e che il espressione:
x.clone().getClass() == x.getClass()
sarà vero, ma questi non sono requisiti assoluti .

Quindi l'intento è per il metodo clone() restituire un oggetto distinto. Sfortunatamente dice che non è un requisito assoluto, il che rende valido il tuo suggerimento, ma continuo a pensare che non sia ragionevole perché non è utile avere un metodo clone che restituisce this. Potrebbe anche causare problemi se si stesse facendo qualcosa di dubbioso come avere uno stato mutabile nelle costanti enumerate o sincronizzarsi su di essi. Il comportamento di tale codice sarebbe diverso a seconda che il metodo clone abbia fatto la corretta clonazione o appena restituito this.

In realtà non si spiega perché si desidera trattare le enumerazioni come Cloneable quando sono intrinsecamente non-clonabili. Voler avere un metodo clone che non obbedisce alle convenzioni accettate sembra un trucco per risolvere un problema più fondamentale con il tuo approccio.

+0

Perché il "contratto" per il metodo 'clone' è restituire una copia. –

+1

@Stephen C: sì, ma non tutti gli oggetti devono aderire a quel contratto, cioè non tutte le classi dovrebbero implementare Cloneable. –

+0

Penso che il Javadoc che hai citato effettivamente supporti il ​​punto OPs: il 99% di tutti i programmatori Java penseranno all'indipendenza in termini di stato dell'oggetto, cioè la modifica dello stato di 'x' non influenzerà lo stato di (il risultato di un precedente) 'x.clone()'. E in questo senso è * molto * ragionevole implementare 'clone()' da 'return this'. Direi che qualsiasi codice basato sulla non identità del risultato 'clone()' è molto più probabile che venga infranto rispetto al codice che passa ** istanze ** immutabili ** ** singleton ** a (terze parti?) metodi che tentano di 'clone()', es per memorizzare lo stato dell'oggetto. – misberner

8

Qual è lo scopo della clonazione di un singleton, se x.clone() == x? Non puoi semplicemente usare x subito.

A rigor di termini, se si desidera clonare qualcosa e far rispettare x.clone() == x, l'unico oggetto che può essere il risultato del clone è x stessa:

def clone() { 
    return this; 
} 

che può essere fuorviante ...


Se si progetta qualcosa e si basano su clone() per la differenziazione, si sta facendo IMHO sbagliato ...

+0

@Christian, il tuo codice ha a che fare con altri oggetti che non implementano Cloneable o tutto deve essere clonabile? –

1

La tua risposta alla tua domanda è la migliore. In generale, la gente si aspetta che clone() restituisca un oggetto diverso. La semantica di Cloneable ha più senso in questo modo. ("L'oggetto è clonabile ... oh, devo essere in grado di fare copie.") Non riesco a pensare a una situazione off-line dove ciò è importante, ma quello era il significato semantico previsto di Cloneable.

Penso che anche se pensassero ai singleton, non l'avrebbero cambiato. Dopotutto, è responsabilità del programmatore decidere cosa può essere clonato e cosa no, aggiungendo (e potenzialmente sovrascrivendo) in modo selettivo l'interfaccia Cloneable e la maggior parte dei programmatori non aggiungerà l'interfaccia Cloneable ai singleton.

+0

Per gli oggetti immutabili, letteralmente l'unica differenza dall'implementazione corretta di 'clone()' e solo 'return this' è il risultato di 'x.clone()! = X', che non hai una vera ragione per preoccuparti. Se ti trovi in ​​una situazione in cui potresti avere un oggetto mutevole o immutabile, creane una copia effettiva. Le copie di oggetti immutabili sono a buon mercato - non è necessario recedere dal grafico degli oggetti, basta assegnare i campi per essere uguali. – Kevin

0

Ma per singleton al contrario voglio che sia x.clone() == x vero.

No, non sarebbe un clone. Così, per single, si desidera che questo:

public Object clone() throws CloneNotSupportedException { 
    throw new CloneNotSupportedException(); 
} 
+1

Sì, dovresti. Un clone ** dovrebbe ** restituire un clone che non ha senso per un singleton. –

+0

Perché vuoi rendere pubblico 'clone'? –

+1

Forse perché questa è la convenzione quando si esegue l'override di 'clone()', vedere http://java.sun.com/javase/6/docs/api/java/lang/Cloneable.html. –

Problemi correlati