pasar - ¿Cómo copio un objeto en Java?
copiar valores de un objeto a otro java (21)
¿Por qué no hay respuesta para usar la API de Reflection?
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;
}
}
Es realmente simple
EDITAR: Incluir objeto hijo a través de recursión
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;
}
}
Considere el siguiente código:
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''
Por lo tanto, quiero copiar el dum
a dumtwo
y cambiar dum
sin afectar al dumtwo
. Pero el código anterior no está haciendo eso. Cuando cambio algo en dum
, el mismo cambio está sucediendo en dumtwo
también.
Supongo que cuando digo dumtwo = dum
, Java solo copia la referencia . Entonces, ¿hay alguna manera de crear una copia nueva de dum
y asignársela a dumtwo
?
Agregue Cloneable
código Cloneable
y debajo de su clase
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
Utilice este clonedObject = (YourClass) yourClassObject.clone();
Aparte de la copia explícita, otro enfoque es hacer que el objeto sea inmutable (sin set
u otros métodos de mutación). De esta manera nunca surge la pregunta. La inmutabilidad se vuelve más difícil con los objetos más grandes, pero ese otro lado es que te empuja en la dirección de la división en pequeños objetos y compuestos coherentes.
Aquí hay una explicación decente de clone()
si terminas por necesitarla ...
Crear un constructor de copia:
class DummyBean {
private String dummy;
public DummyBean(DummyBean another) {
this.dummy = another.dummy; // you can access
}
}
Cada objeto tiene también un método de clonación que se puede usar para copiar el objeto, pero no lo use. Es demasiado fácil crear una clase y hacer un método de clonación incorrecto. Si vas a hacer eso, lee al menos lo que Joshua Bloch tiene que decir al respecto en Effective Java .
Deep Cloning es su respuesta, que requiere implementar la interfaz Cloneable
y reemplazar el 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;
}
}
Lo llamará así DummyBean dumtwo = dum.clone();
En el paquete import org.apache.commons.lang.SerializationUtils;
hay un metodo
SerializationUtils.clone(Object);
Ejemplo:
this.myObjectCloned = SerializationUtils.clone(this.object);
Esto funciona tambien Asumiendo modelo
class UserAccount{
public int id;
public String name;
}
Primero agregue compile ''com.google.code.gson:gson:2.8.1''
a su aplicación> gradle & sync. Entonces
Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);
Puede excluir el uso de un campo utilizando transient
palabra clave transient
después del modificador de acceso.
Nota: Esta es una mala práctica. Tampoco recomiendo usar Cloneable
o JavaSerialization
Es lento y está roto. Escribir copia de constructor para el mejor rendimiento 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);
}
}
Estadísticas de prueba de 90000 iteración:
Línea UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);
toma 808ms
Línea UserAccount clone = new UserAccount(aO);
toma menos de 1 ms
Conclusión: usa gson si tu jefe está loco y prefieres la velocidad. Usa el segundo constructor de copias si prefieres calidad.
También puede usar el complemento generador de código de constructor de copia en Android Studio.
Para hacer eso tienes que clonar el objeto de alguna manera. Aunque Java tiene un mecanismo de clonación, no lo use si no tiene que hacerlo. Cree un método de copia que haga el trabajo de copia por usted, y luego haga:
dumtwo = dum.copy();
Here hay algunos consejos más sobre diferentes técnicas para lograr una copia.
Pase el objeto que desea copiar y obtenga el objeto que desea:
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;
}
Ahora analiza el objDest
en el objeto deseado.
¡Feliz codificación!
Puede realizar copias en profundidad automáticamente con XStream, desde http://x-stream.github.io/ :
XStream es una biblioteca simple para serializar objetos a XML y viceversa.
Agrégalo a tu proyecto (si usas maven)
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.3.1</version>
</dependency>
Entonces
DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));
Con esto tienes una copia sin la necesidad de implementar ninguna interfaz de clonación.
Puedes intentar implementar Cloneable
y usar el método clone()
; sin embargo, si usa el método de clonación, debería, por norma general, SIEMPRE anular el método public Object clone()
.
Sí, solo estás haciendo una referencia al objeto. Puede clonar el objeto si implementa Cloneable
.
Echa un vistazo a este artículo wiki sobre la copia de objetos.
Sí. Necesitas hacer una copia profunda de tu objeto.
Si puede agregar una anotación al archivo de origen, se puede usar un procesador de anotaciones o un generador de código como este .
import net.zerobuilder.BeanBuilder
@BeanBuilder
public class DummyBean {
// bean stuff
}
Se DummyBeanBuilders
una clase DummyBeanBuilders
, que tiene un método estático dummyBeanUpdater
para crear copias poco profundas, de la misma manera que lo haría manualmente.
DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
Solo sigue como sigue:
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();
}
}
y donde quiera que desee obtener otro objeto, simplemente realice la clonación. p.ej:
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
Utilice una utilidad de clonación profunda:
SomeObjectType copy = new Cloner().deepClone(someObject);
Esto hará una copia profunda de cualquier objeto java, échale un vistazo en https://github.com/kostaskougios/cloning
Utilizo la biblioteca JSON de Google para serializarla y luego crear una nueva instancia del objeto serializado. Hace copia profunda con algunas restricciones:
no puede haber referencias recursivas
no copiará matrices de tipos dispares
Las matrices y listas deben escribirse o no encontrará la clase para crear instancias.
Es posible que necesite encapsular cadenas en una clase que se declara a sí mismo
También utilizo esta clase para guardar las preferencias del usuario, las ventanas y otras cosas para volver a cargar en el tiempo de ejecución. Es muy fácil de usar y 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;
}
}
Básico: Copia de objetos en Java.
Supongamos un objeto- obj1
, que contiene dos objetos, contenidaObj1 y contenidaObj2 .
Copia superficial:
la copia superficial crea una nueva instance
de la misma clase y copia todos los campos a la nueva instancia y la devuelve. La clase de objeto proporciona un método de clone
y proporciona soporte para la copia superficial.
Copia profunda:
Una copia profunda se produce cuando un objeto se copia junto con los objetos a los que se refiere . La imagen de abajo muestra obj1
después de realizar una copia profunda en él. No solo se ha copiado obj1
, sino que también se han copiado los objetos que contiene. Podemos usar Java Object Serialization
para hacer una copia profunda. Desafortunadamente, este enfoque también tiene algunos problemas ( ejemplos detallados ).
Posibles problemas:
clone
es difícil de implementar correctamente.
Es mejor usar Copia defensiva , constructores de copia (como respuesta @egaga) o métodos de fábrica estáticos .
- Si tiene un objeto, sabe que tiene un método público
clone()
, pero no sabe el tipo del objeto en el momento de la compilación, entonces tiene un problema. Java tiene una interfaz llamadaCloneable
. En la práctica, deberíamos implementar esta interfaz si queremos hacer un objetoCloneable
.Object.clone
está protegido , por lo que debemos anularlo con un método público para que sea accesible. - Otro problema surge cuando intentamos copiar en profundidad un objeto complejo . Supongamos que el método
clone()
de todas las variables de objeto miembro también hace una copia profunda, esto es demasiado arriesgado como una suposición. Debes controlar el código en todas las clases.
Por ejemplo, org.apache.commons.lang.SerializationUtils tendrá un método para la clonación profunda utilizando la serialización ( Source ). Si necesitamos clonar Bean, hay un par de métodos de utilidad en org.apache.commons.beanutils ( Source ).
-
cloneBean
un bean en función de los captadores y establecedores de propiedades disponibles, incluso si la propia clase de bean no implementa Cloneable. -
copyProperties
los valores de propiedad del bean de origen en el bean de destino para todos los casos en los que los nombres de propiedad sean los mismos.
class DB {
private String dummy;
public DB(DB one) {
this.dummy = one.dummy;
}
}
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();
}
}
}
y en su código:
MyClass myClass = new MyClass();
// do some work with this object
MyClass clonedMyClass = myClass.clone();