Respostas:
O fato de o clone ser protegido é extremamente duvidoso - assim como o fato de o clone
método não ser declarado na Cloneable
interface.
Isso torna o método bastante inútil para fazer cópias de dados porque você não pode dizer :
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
Acho que o design do Cloneable
agora é amplamente considerado um erro (citação abaixo). Eu normalmente gostaria de poder fazer implementações de uma interface, Cloneable
mas não necessariamente fazer a interfaceCloneable
(semelhante ao uso de Serializable
). Isso não pode ser feito sem reflexão:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Citação de Josh Bloch's Effective Java :
"A interface clonável foi concebida como uma interface mixin para objetos para anunciar que permitem a clonagem. Infelizmente, ela falha em atender a esse propósito ... Este é um uso altamente atípico de interfaces e não deve ser emulado ... Para que a implementação da interface tenha algum efeito em uma classe, ela e todas as suas superclasses devem obedecer a um protocolo bastante complexo, não executável e amplamente não documentado "
Serializable
- cabe às implementações decidir se a implementar Serializable
. Eu estava estendendo isso para Cloneable
- não é algo que uma interface deva estender - mas a implementação de uma interface é gratuita Cloneable
. O problema é que, se você tem um parâmetro do tipo de interface, pergunta se ele é clonável; mas não é possível cloná-lo!
A interface Clonable é apenas um marcador dizendo que a classe pode suportar clone. O método é protegido porque você não deve chamá-lo no objeto, você pode (e deve) sobrescrevê-lo como público.
Da Sun:
Na classe Object, o método clone () é declarado protegido. Se tudo o que você fizer for implementar Cloneable, apenas as subclasses e membros do mesmo pacote serão capazes de invocar clone () no objeto. Para permitir que qualquer classe em qualquer pacote acesse o método clone (), você terá que sobrescrevê-lo e declará-lo público, como é feito a seguir. (Ao substituir um método, você pode torná-lo menos privado, mas não mais privado. Aqui, o método clone () protegido em Object está sendo substituído como um método público.)
Set
clone
está protegido porque é algo que deve ser sobrescrito para que seja específico para a classe atual. Embora fosse possível criar um clone
método público que clonaria qualquer objeto, isso não seria tão bom quanto um método escrito especificamente para a classe que precisa dele.
O método Clone não pode ser usado diretamente em nenhum objeto, e é por isso que ele deve ser sobrescrito pela subclasse.
Claro que poderia ser público e apenas lançar uma exceção apropriada quando a clonagem não for possível, mas acho que seria enganoso.
A maneira como o clone está implementado agora faz você pensar sobre por que deseja usar o clone e como deseja que seu objeto seja clonado.
Ele é protegido porque a implementação padrão faz uma cópia superficial de todos os campos (incluindo privado), contornando o construtor . Isso não é algo que um objeto possa ser projetado para tratar em primeiro lugar (por exemplo, ele pode controlar as instâncias do objeto criado em uma lista compartilhada ou algo semelhante).
Pelo mesmo motivo, a implementação padrão de clone()
lançará se o objeto no qual é chamado não implementar Cloneable
. É uma operação potencialmente insegura com consequências de longo alcance e, portanto, o autor da classe deve aceitar explicitamente.
Do javadoc de clonável.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
Portanto, você poderia chamar clone em cada objeto, mas isso não lhe daria na maioria das vezes os resultados desejados ou uma exceção. Mas só é encorajado se você implementar clonável.
IMHO é tão simples quanto isto:
#clone
não deve ser chamado em objetos não clonáveis, portanto, não é tornado público#clone
deve ser chamado por subclasses ob Object
que implementam Cloneable para obter a cópia superficial da classe certaQual é o escopo correto para métodos que devem ser chamados por subclasses, mas não por outras classes?
É protected
.
A implementação Cloneable
de classes, é claro, tornará esse método público para que ele possa ser chamado de outras classes.
O método Clone () tem uma verificação interna de 'instância de Cloneable ou não'. É assim que a equipe Java pode pensar que restringirá o uso impróprio do método clone (). O método clone () é protegido, ou seja, acessado apenas por subclasses. Uma vez que object é a classe pai de todas as subclasses, o método Clone () pode ser usado por todas as classes de fato se não tivermos a verificação acima de 'instância de Cloneable'. Esta é a razão pela qual a equipe Java pode ter pensado em restringir o uso impróprio de clone (), tendo a verificação no método clone () 'é uma instância de Cloneable'.
Portanto, qualquer classe que implemente clonável pode usar o método clone () da classe Object.
Além disso, por ser protegido, está disponível apenas para as subclasses que implementam interface clonável. Se quisermos torná-lo público, esse método deve ser substituído pela subclasse com sua própria implementação.
Sim, mesmo problema que conheci. Mas eu resolvo isso implementando este código
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Exatamente como alguém disse antes.
Bem, também os desenvolvedores do sol são apenas humanos e, de fato, cometeram um grande erro ao implementar o método clone como protegido, o mesmo erro que implementaram um método clone não funcional em ArrayList! Portanto, em geral, existe um mal-entendido muito mais profundo, mesmo de programadores Java experientes, sobre o método clone.
No entanto, recentemente encontrei uma solução rápida e fácil para copiar qualquer objeto com todo o seu conteúdo, não importa como seja construído e o que contenha, veja minha resposta aqui: Bug no uso de Object.clone ()
Mais uma vez, a estrutura Java JDK mostra um pensamento brilhante:
A interface clonável não contém um "clone T público ();" método porque atua mais como um atributo (por exemplo, Serializable) que permite que uma instância seja clonada.
Não há nada de errado com este design porque:
Object.clone () não fará o que você deseja com sua classe personalizada.
Se você tem Myclass implementa Cloneable => você sobrescreve clone () com "public MyClass clone ()"
Se você tiver MyInterface extends Cloneable e algumas MyClasses implementando MyInterface: simplesmente defina "public MyInterface clone ();" na interface e todos os métodos que usam objetos MyInterface serão capazes de cloná-los, não importando sua classe MyClass.