Pergunta

Considere o código abaixo:

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'

Então, eu quero copiar o dum para dumtwo e mudança dum sem afetar o dumtwo. Mas o código acima não está fazendo isso. Quando eu mudar alguma coisa em dum, a mesma mudança está acontecendo em dumtwo também.

Eu acho que, quando eu digo dumtwo = dum, cópias Java referência somente . Então, há alguma maneira de criar uma nova cópia do dum e atribuí-la a dumtwo?

Foi útil?

Solução

Criar um construtor de cópia:

class DummyBean {
  private String dummy;

  public DummyBean(DummyBean another) {
    this.dummy = another.dummy; // you can access  
  }
}

Cada objeto tem também um método clone que pode ser usado para copiar o objeto, mas não usá-lo. É muito fácil criar uma classe e fazer método clone imprópria. Se você estiver indo para fazer isso, leia pelo menos o que Joshua Bloch tem a dizer sobre isso em Effective Java .

Outras dicas

básica:. Objeto Copiar em Java

Vamos assumir uma obj1 a objetos, que contém dois objetos, containedObj1 e containedObj2 .
enter descrição da imagem aqui

rasa copiar:
cópia rasa cria um novo instance da mesma classe e copia todos os campos para a nova instância e devolve-lo. classe Object fornece um método clone e fornece suporte para a cópia superficial.
enter descrição da imagem aqui

Deep copiar:
Uma cópia profunda ocorre quando um objeto é copiado juntamente com os objetos a que se refere . Abaixo mostra a imagem obj1 depois de uma cópia profunda foi realizada nele. Não só tem sido obj1 Copiado , mas os objetos contidos dentro dele foram copiados também. Podemos usar Java Object Serialization para fazer uma cópia profunda. Infelizmente, esta abordagem tem alguns problemas também ( exemplos detalhados ) .
enter descrição da imagem aqui

Problemas possíveis:
clone é complicado para implementar corretamente.
É melhor usar a cópia defensiva , copiar construtores (como resposta @egaga) ou métodos de fábrica estáticos .

  1. Se você tem um objeto, que você conhece tem um método clone() público, mas você não sabe o tipo de objeto em tempo de compilação, então você tem problema. Java tem uma interface chamada Cloneable. Na prática, devemos implementar essa interface, se quisermos fazer uma Cloneable objeto. Object.clone é protegido , por isso temos de substituir -lo com um método público para que ele seja acessível.
  2. Outro problema surge quando tentamos cópia profunda de um objeto complexo . Suponha que o método clone() de todas as variáveis ??membro do objeto também faz cópia profunda, isso é muito arriscado de uma suposição. Você deve controlar o código em todas as classes.

Por exemplo org.apache.commons.lang.SerializationUtils terá método para Deep clone usando serialização ( Fonte ). Se precisamos clone feijão, em seguida, existem alguns métodos utilitários em org.apache.commons.beanutils ( Fonte ).

  • cloneBean irá clonar um feijão com base nos getters de propriedade disponíveis e setters, mesmo se a classe de feijão em si não implementa Cloneable.
  • copyProperties irá copiar os valores de propriedade do feijão origem ao feijão destino para todos os casos em que os nomes das propriedades são os mesmos.

No import org.apache.commons.lang.SerializationUtils; pacote há um método:

SerializationUtils.clone(Object);

Exemplo:

this.myObjectCloned = SerializationUtils.clone(this.object);

Basta seguir como abaixo:

public class Deletable implements Cloneable{

    private String str;
    public Deletable(){
    }
    public void setStr(String str){
        this.str = str;
    }
    public void display(){
        System.out.println("The String is "+str);
    }
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

e onde quer que você deseja obter um outro objeto, simples executar a clonagem. por exemplo:

Deletable del = new Deletable();
Deletable delTemp = (Deletable ) del.clone(); // this line will return you an independent
                                 // object, the changes made to this object will
                                 // not be reflected to other object

Por que não há resposta para usar Reflection API?

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                field.set(clone, field.get(obj));
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

É realmente simples.

EDIT: Incluir objeto filho via recursão

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                if(field.getType().isPrimitive() || field.getType().equals(String.class)
                        || field.getType().getSuperclass().equals(Number.class)
                        || field.getType().equals(Boolean.class)){
                    field.set(clone, field.get(obj));
                }else{
                    Object childObj = field.get(obj);
                    if(childObj == obj){
                        field.set(clone, clone);
                    }else{
                        field.set(clone, cloneObject(field.get(obj)));
                    }
                }
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

Eu uso biblioteca JSON do Google para serializar-lo em seguida, criar uma nova instância do objeto serializado. Ele faz cópia profunda com algumas restrições:

  • não pode haver qualquer referência recursiva

  • não vai copiar matrizes de tipos diferentes

  • matrizes e listas devem ser digitados ou não vai encontrar a classe para instanciar

  • Você pode precisar de cordas Encapsular em uma classe que você declarar-se

Eu também usar essa classe para salvar as preferências do usuário, janelas e outros enfeites para ser recarregado em tempo de execução. É muito fácil de usar e eficaz.

import com.google.gson.*;

public class SerialUtils {

//___________________________________________________________________________________

public static String serializeObject(Object o) {
    Gson gson = new Gson();
    String serializedObject = gson.toJson(o);
    return serializedObject;
}
//___________________________________________________________________________________

public static Object unserializeObject(String s, Object o){
    Gson gson = new Gson();
    Object object = gson.fromJson(s, o.getClass());
    return object;
}
       //___________________________________________________________________________________
public static Object cloneObject(Object o){
    String s = serializeObject(o);
    Object object = unserializeObject(s,o);
    return object;
}
}

Sim, você está apenas fazendo uma referência para o objeto. Você pode clonar o objeto se ele implementa Cloneable.

Confira este artigo wiki sobre como copiar objetos.

Consulte aqui: cópia Objeto

Sim. Você precisa profunda Copiar seu objeto.

Adicionar Cloneable e código abaixo para sua classe

public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

Use este clonedObject = (YourClass) yourClassObject.clone();

Isso funciona também. Assumindo modelo

class UserAccount{
   public int id;
   public String name;
}

Primeiro add compile 'com.google.code.gson:gson:2.8.1' ao seu aplicativo> Gradle e sincronização. Então

Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);

Você pode excluir usando um campo usando palavra-chave transient após modificador de acesso.

Nota: Esta é uma prática ruim. Também não recomendamos a utilização Cloneable ou JavaSerialization É lento e quebrado. Escrever construtor de cópia para o melhor desempenho ref .

Algo como

class UserAccount{
        public int id;
        public String name;
        //empty constructor
        public UserAccount(){}
        //parameterize constructor
        public UserAccount(int id, String name) {
            this.id = id;
            this.name = name;
        }

        //copy constructor
        public UserAccount(UserAccount in){
            this(in.id,in.name);
        }
    }

estatísticas de teste de 90000 iteração:
UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); linha leva 808ms

Linha UserAccount clone = new UserAccount(aO); leva menos de 1 ms

Conclusão: Use Gson se seu chefe é louco e você prefere velocidade. Use segundo construtor de cópia se você preferir qualidade.

Você também pode usar o código de construtor de cópia gerador de plugin no Android Studio.

Aqui está uma explicação decente de clone() se você acabar precisando dele ...

aqui: clone (método Java)

Deep clonagem é a sua resposta, o que requer a implementação da interface Cloneable e substituindo o método clone().

public class DummyBean implements Cloneable {

   private String dummy;

   public void setDummy(String dummy) {
      this.dummy = dummy;
   }

   public String getDummy() {
      return dummy;
   }

   @Override
   public Object clone() throws CloneNotSupportedException {
      DummyBean cloned = (DummyBean)super.clone();
      cloned.setDummy(cloned.getDummy());
      // the above is applicable in case of primitive member types, 
      // however, in case of non primitive types
      // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
      return cloned;
   }
}

Você vai chamá-lo assim DummyBean dumtwo = dum.clone();

Use um utilitário de clonagem profunda:

SomeObjectType copy = new Cloner().deepClone(someObject);

Isso irá copiar profunda qualquer objeto java, verificá-la em https://github.com/kostaskougios/cloning

Para fazer isso você tem que clonar o objeto de alguma forma. Embora Java tem um mecanismo de clonagem, não usá-lo se você não tem que. Criar um método de cópia que faz o trabalho de cópia para você, e, em seguida, fazer:

dumtwo = dum.copy();

Aqui é mais alguns conselhos sobre técnicas diferentes para a realização de uma cópia.

Além de copiar explicitamente, uma outra abordagem é fazer o imutável objeto (sem set ou outros métodos modificadores). Desta forma, a questão nunca surge. Imutabilidade torna-se mais difícil com objetos maiores, mas que o outro lado disso é que ele empurra-lo na direção de dividir em pequenos objetos e compósitos coerentes.

class DB {
  private String dummy;

  public DB(DB one) {
    this.dummy = one.dummy; 
  }
}

Você pode profunda copiar automaticamente com XStream, de http://x-stream.github.io/:

XStream é uma biblioteca simples de objetos serialize para XML e volta novamente.

Adicione ao seu projeto (se estiver usando Maven)

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.3.1</version>                
</dependency>

Em seguida

DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));

Com isso, você tem uma cópia, sem a necessidade de implementar qualquer interface de clonagem.

public class MyClass implements Cloneable {

private boolean myField= false;
// and other fields or objects

public MyClass (){}

@Override
public MyClass clone() throws CloneNotSupportedException {
   try
   {
       MyClass clonedMyClass = (MyClass)super.clone();
       // if you have custom object, then you need create a new one in here
       return clonedMyClass ;
   } catch (CloneNotSupportedException e) {
       e.printStackTrace();
       return new MyClass();
   }

  }
}

e em seu código:

MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();

Passe o objeto que você deseja copiar e obter o objeto que você deseja:

private Object copyObject(Object objSource) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(objSource);
            oos.flush();
            oos.close();
            bos.close();
            byte[] byteData = bos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
            try {
                objDest = new ObjectInputStream(bais).readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return objDest;

    }

Agora analisar o objDest ao objeto desejado.

Happy Coding!

Você pode tentar implementar Cloneable e usar o método clone(); No entanto, se você usar o método clone você deve - por padrão -. método Object sempre substituem do public Object clone()

Se você pode adicionar uma anotação ao arquivo de origem, um gerador de processador de anotação ou código como esta pode ser usado.

import net.zerobuilder.BeanBuilder

@BeanBuilder
public class DummyBean { 
  // bean stuff
}

A DummyBeanBuilders classe será gera, que tem um dummyBeanUpdater método estático para criar cópias rasas, da mesma forma que você iria fazê-lo manualmente.

DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top