Pergunta

É tarde demais para mudar a pergunta, mas mais precisa teria sido de perguntar "Por que o clone () não permite singletons?". Um método copy() seria mais conveniente.


Existe alguma razão para que enums em Java não pode ser clonado?

O manual diz que

Isso garante que enums nunca são clonados, o que é necessário para preservar seu status "singleton".

Mas voltando a instância em si também preservar seu status, e eu seria capaz de lidar com enums associados da mesma forma que outros objetos clonable.

Pode-se argumentar que

A intenção geral [do clone ()] é que, para qualquer objecto x, a expressão: x.clone() != x será verdade, [...]

Mas para singletons no x.clone() == x eu quero contrário para ser verdade. Se a instância em si seria devolvido, então o padrão Singleton seria transparente para fazer referência a objetos.

Então, por que enums não tem permissão para ser clonado ou eles se esqueça de pensar sobre singletons e imutáveis, quando clone() foi especificado?

Foi útil?

Solução

Mas para singletons, pelo contrário, eu quero x.clone() == x para ser verdade.

Você pode querer, mas eu acho que é estranho que o seguinte código iria quebrar:

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?

(Claro, desde que clone() só dá cópias rasas, até mesmo uma correcta execução pode causar erros no código acima.)

Por outro lado, eu posso tipo de concordar que não faria sentido para a clonagem de operações para apenas return this para objetos imutáveis, e enums realmente deve ser imutável. Agora, quando o contrato para clone() foi escrito, eles aparentemente não pensar sobre imutáveis, ou eles não queriam um caso especial para um conceito que não é suportado pela linguagem (ou seja, tipos imutáveis).

E assim, clone() é o que é, e você não pode muito bem ir e mudar algo que tem sido em torno desde Java 1.0. Estou certo de que em algum lugar lá fora, não há código que totalmente depende de clone() retornar um novo objeto, distinto, talvez como uma chave para uma IdentityHashMap ou algo assim.

Outras dicas

Qual é a finalidade da clonagem de um singleton, se x.clone() == x? Você não pode simplesmente usar x imediatamente.

A rigor, se você quiser clone algo e impor x.clone() == x, o único objeto que pode ser o resultado do clone é x-se:

def clone() {
  return this;
}

Que pode ser enganosa ...


Se você está projetando algo e são baseados em clone() para a diferenciação, você está fazendo isso IMHO errado ...

Se o método Clone Retorna this exemplo, em vez de um objeto distinto, então não é um clone, é?

O Javadoc diz:

Por convenção, o objeto retornado por este método deve ser independente da este objecto (que está a ser clonado).

Enums não devem ser clonados, porque não é suposto para sempre apenas ser uma instância de cada valor.

EDIT: Em resposta à seguinte comentário:

Isso é exatamente o que eu critico. Por quê não retornar o mesmo exemplo, se houver Não pode ser um diferente?

Porque não faz muito sentido. Se for o mesmo objeto, então não é um clone. O Javadocs dizer também:

A intenção geral é que, para qualquer objecto X, a expressão:

x.clone() != x
será verdade, e que a expressão:
x.clone().getClass() == x.getClass()
será verdade, mas estes não são requisitos absolutos.

Assim, a intenção é que o método clone() para retornar um objeto distinto. Infelizmente ele diz que não é uma exigência absoluta, o que torna a sua sugestão válida, mas eu ainda acho que não é sensato porque não é útil ter um método clone que os retornos this. Pode até causar problemas se você estivesse fazendo algo duvidoso como ter estado mutável em suas constantes enum ou sincronizar sobre eles. O comportamento de tal código seria diferente, dependendo se o método clone fez clonagem adequado ou this acabado de voltar.

Você não realmente explicar por que você quer tratar enums como Cloneable quando eles são inerentemente un-cloneable. Querer ter um método clone que não obedece as convenções aceitas parece ser um hack para resolver algum problema mais fundamental com a sua abordagem.

Eu acho que eles não queriam singletons tratar como um caso especial quando clone() foi especificado. Que teria complicado a especificação. Portanto, agora os desenvolvedores de biblioteca tem que tratá-los como um caso especial, mas para o resto de nós, é bom que podemos confiar que x.clone() != x.

A sua própria resposta à sua pergunta é o melhor. Em geral, as pessoas esperam clone() para devolver um objeto diferente. A semântica de Cloneable-se fazer mais sentido assim. ( "O objeto é cloneable ... oh, eu devo ser capaz de fazer cópias.") Eu não posso pensar em uma situação de improviso, onde que importa, mas que era o significado semântico de Cloneable pretendido.

Eu acho que mesmo se eles estavam pensando sobre singletons, eles não mudaram isso. Afinal de contas, é responsabilidade do programador para decidir o que pode ser clonado eo que não pode, adicionando seletivamente (e potencialmente substituir) a interface Cloneable, e a maioria dos programadores não vão adicionar a interface Cloneable para singletons também.

Mas para singletons, pelo contrário, eu quero x.clone() == x para ser verdade.

Não, isso não seria um clone. Assim, para singletons, você quer este:

public Object clone() throws CloneNotSupportedException {
  throw new CloneNotSupportedException(); 
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top