Eu estava procurando alguns tutoriais explicando sobre Java Cloneable
, mas não consegui nenhum link bom, e Stack Overflow está se tornando a escolha mais óbvia de qualquer maneira.
Eu gostaria de saber o seguinte:
Cloneable
significa que podemos ter um clone ou uma cópia dos objetos, implementando aCloneable
interface. Quais são as vantagens e desvantagens de fazer isso?- Como a clonagem recursiva acontece se o objeto é um objeto composto?
Respostas:
A primeira coisa que você deve saber
Cloneable
é - não o use.É muito difícil implementar a clonagem com
Cloneable
razão, e o esforço não vale a pena.Em vez disso, use algumas outras opções, como apache-commons
SerializationUtils
(clone profundo) ouBeanUtils
(clone raso), ou simplesmente use um construtor de cópia.Veja aqui as opiniões de Josh Bloch sobre a clonagem com
Cloneable
, o que explica as muitas desvantagens dessa abordagem. ( Joshua Bloch era um funcionário da Sun e liderou o desenvolvimento de vários recursos Java.)fonte
static
métodos em interfaces, então apenas forneça umstatic WhatEverTheInterface copy(WhatEverTheInterface initial)
? mas eu me pergunto o que isso oferece, já que você copia campos de um objeto durante a clonagem, mas uma interface define apenas métodos. cuidado para explicar?O próprio Cloneable é, infelizmente, apenas uma interface de marcador, isto é: ele não define o método clone ().
O que isso faz é alterar o comportamento do método protegido Object.clone (), que lançará uma CloneNotSupportedException para classes que não implementam Cloneable e executará uma cópia superficial do membro para classes que o fazem.
Mesmo que esse seja o comportamento que você está procurando, você ainda precisará implementar seu próprio método clone () para torná-lo público.
Ao implementar seu próprio clone (), a ideia é começar com o objeto criado por super.clone (), que é garantido ser da classe correta, e então fazer qualquer preenchimento adicional de campos caso uma cópia superficial não seja o que você quer. Chamar um construtor de clone () seria problemático, pois isso quebraria a herança no caso de uma subclasse desejar adicionar sua própria lógica clonável adicional; se fosse chamar super.clone (), ele obteria um objeto da classe errada neste caso.
Essa abordagem ignora qualquer lógica que possa ser definida em seus construtores, o que pode ser potencialmente problemático.
Outro problema é que quaisquer subclasses que esquecerem de substituir clone () herdarão automaticamente a cópia superficial padrão, o que provavelmente não é o que você deseja no caso de estado mutável (que agora será compartilhado entre a fonte e a cópia).
A maioria dos desenvolvedores não usa o Cloneable por esses motivos e simplesmente implementa um construtor de cópia.
Para obter mais informações e possíveis armadilhas de Cloneable, recomendo o livro Effective Java de Joshua Bloch
fonte
Portanto, use o Cloneable criteriosamente. Não oferece benefícios suficientes em comparação com o esforço que você precisa aplicar para fazer tudo certo.
fonte
A clonagem é um paradigma de programação básico. O fato de que o Java pode ter implementado mal em muitos aspectos não diminui a necessidade de clonagem. E é fácil implementar a clonagem que funcionará da maneira que você quiser, superficial, profunda, mista, o que for. Você pode até usar o nome clone para a função e não implementar Cloneable, se desejar.
Suponha que eu tenha classes A, B e C, onde B e C são derivados de A. Se eu tiver uma lista de objetos do tipo A como esta:
Agora, essa lista pode conter objetos do tipo A, B ou C. Você não sabe de que tipo são os objetos. Portanto, você não pode copiar a lista desta forma:
Se o objeto for realmente do tipo B ou C, você não obterá a cópia correta. E se A for abstrato? Agora, algumas pessoas sugeriram isto:
Esta é uma ideia muito, muito ruim. E se você adicionar um novo tipo derivado? E se B ou C estiverem em outro pacote e você não tiver acesso a eles nesta aula?
O que você gostaria de fazer é:
Muitas pessoas indicaram por que a implementação básica do Java do clone é problemática. Mas, é facilmente superado desta forma:
Na classe A:
Na classe B:
Na classe C:
Não estou implementando Cloneable, apenas usando o mesmo nome de função. Se você não gosta disso, dê outro nome.
fonte
A) Não há muitas vantagens do clone sobre um construtor de cópia. Provavelmente, o maior deles é a capacidade de criar um novo objeto exatamente do mesmo tipo dinâmico (assumindo que o tipo declarado é clonável e tem um método clone público).
B) O clone padrão cria uma cópia superficial e permanecerá uma cópia superficial, a menos que sua implementação de clone mude isso. Isso pode ser difícil, especialmente se sua classe tiver campos finais
Bozho está certo, clonar pode ser difícil de acertar. Um construtor / fábrica de cópias atenderá à maioria das necessidades.
fonte
Quais são as desvantagens do clonável?
A clonagem é muito perigosa se o objeto que você está copiando tem composição. Você precisa pensar sobre o possível efeito colateral neste caso, porque o clone cria uma cópia superficial:
Digamos que você tenha um objeto para lidar com a manipulação relacionada ao banco de dados. Diga, esse objeto tem
Connection
objeto como uma das propriedades.Então, quando alguém cria um clone de
originalObject
, O objeto sendo criado, digamoscloneObject
,. Aqui, ooriginalObject
ecloneObject
mantém a mesma referência paraConnection
objeto.Digamos que
originalObject
feche oConnection
objeto, então agora ocloneObject
não funcionará porque oconnection
objeto foi compartilhado entre eles e na verdade foi fechado pelooriginalObject
.Problema semelhante pode ocorrer se você quiser clonar um objeto que tem IOStream como uma propriedade.
Como a clonagem recursiva acontece se o objeto é um objeto composto?
A clonagem executa uma cópia superficial. O significado é que os dados do objeto original e do objeto clone apontarão para a mesma referência / memória. ao contrário, no caso de cópia profunda, os dados da memória do objeto original são copiados para a memória do objeto clone.
fonte
Cloneable
não executa uma cópia,Object.clone
faz. "Os dados da memória do objeto original são copiados para a memória do objeto clone" é exatamente oObject.clone
que o faz. Você precisa falar sobre a memória de objetos referenciados para descrever a cópia profunda.