首页 > 代码库 > Java - deep clone
Java - deep clone
先让我描述一下问题:
我在某Action(struts2.x)-A中写了一个功能P,以当前用户的某个标识F == 1时需要走这个功能,而且这个功能因某些原因已经侵入到了其他一些method中。
顺便一提,A中获得当前用户session的method已经被父类封装好了。
然后我的代码已经push上去了,第二天有人告诉我能不能暂时去掉这个功能。
一个个注释掉太麻烦了,
于是我决定在这个A中override获得当前用户session的method,并将F赋值为0。
于是我只需要来个shallow copy就可以了。
比如我可以这样:
给User来个implements Clonable
然后在getUserInfo()的Override中clone一个出来再赋值setF(0)
但这也许不太好,毕竟我需要动User。
我可以直接使用org.springframework.beans.BeanUtils.copyPropergties(source,target)
看了看源码,里面又是sourcepd又是targetpd,pd是什么?
就当他是用来描述java bean的媒介好了。
当然,他也是shallow copy...
for (PropertyDescriptor targetPd : targetPds) { if (targetPd.getWriteMethod() != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null && sourcePd.getReadMethod() != null) { try { Method readMethod = sourcePd.getReadMethod(); if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); Method writeMethod = targetPd.getWriteMethod(); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } catch (Throwable ex) { throw new FatalBeanException("Could not copy properties from source to target", ex); } } }}
无论如何,这个已经解决我的问题了,A中调用getUserInfo()都是我clone的User,不会影响其他的Action.
但如果我那天用User下某个引用类型的Field的某个simple type的Field做标记呢?
那我得deep clone,平时掌握的类库不多,让我自己解决的话我怎么弄?
也许我可以这样做:
File f = new File("@#$%^&*");f.createNewFile();ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));oos.writeObject(u0);
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f));
u1 = (User)ois.readObject();
光看一小段代码感觉是个简单粗暴的好办法,只不过我得User及其下那些引用类型加上implements Serializable...
后来我找到了这样一个东西:
<dependencies> <dependency> <groupId>uk.com.robust-it</groupId> <artifactId>cloning</artifactId> <version>1.9.0</version> </dependency></dependencies>
可以这样使用:
com.rits.cloning.Cloner cloner = new com.rits.cloning.Cloner();u1 = cloner.deepClone(u0);u1.getPet().setName("papapa"); System.out.println(u0);System.out.println(u1);
输出结果是clone后的u1的pet的名字变成了papapa而作为clone source的u0没有任何变化,这就是deep clone.
忽略clone source是数组的情况,这个类进行deep clone的关键部分如下:
for (final Field field : fields) { final int modifiers = field.getModifiers(); if (!Modifier.isStatic(modifiers)) { if (nullTransient && Modifier.isTransient(modifiers)) { // request by Jonathan : transient fields can be null-ed final Class<?> type = field.getType(); if (!type.isPrimitive()) { field.set(newInstance, null); } } else { final Object fieldObject = field.get(o); final boolean shouldClone = (cloneSynthetics || (!cloneSynthetics && !field.isSynthetic())) && (cloneAnonymousParent || ((!cloneAnonymou sParent && !isAnonymousParent(field)))); final Object fieldObjectClone = clones != null ? (shouldClone ? cloneInternal(fieldObject, clones) : fieldObject) : fieldObject; field.set(newInstance, fieldObjectClone); if (dumpClonedClasses && fieldObjectClone != fieldObject) { System.out.println("cloned field>" + field + " -- of class " + o.getClass()); } } }}
递归下去找field的引用的引用的引用的引用....然后全是他们newInstance...
Java - deep clone