任意のJAVAオブジェクトの深度コピー


任意のJAVAオブジェクト(Cloneableインタフェースまたはシーケンス化インタフェースを実装するかどうかにかかわらず)を深度コピーする必要がある場合がありますが、BeanUtilsはあまり使いにくいことがわかり、以下のツールクラスを書いて深度コピーを行います.

package com.n_app.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 *      
 * @author [email protected]
 *
 */
public class Clone {
	/**
	 *              
	 */
	static Class[] needlessCloneClasses = new Class[]{String.class,Boolean.class,Character.class,Byte.class,Short.class,
		Integer.class,Long.class,Float.class,Double.class,Void.class,Object.class,Class.class
	};
	/**
	 *              
	 * @param c     
	 * @return            ,     
	 */
	private static boolean isNeedlessClone(Class c){
		if(c.isPrimitive()){//    
			return true;
		}
		for(Class tmp:needlessCloneClasses){//            
			if(c.equals(tmp)){
				return true;
			}
		}
		return false;
	}
	
	/**
	 *        
	 * @param c     
	 * @return     
	 * @throws IllegalAccessException
	 */
	private static Object createObject(Object value) throws IllegalAccessException{
			try {
				return value.getClass().newInstance();
			} catch (InstantiationException e) {
				return null;
			} catch (IllegalAccessException e) {
				throw e;
			}
	}
	
	/**
	 *       
	 * @param value     
	 * @param level     。  0     ,           Object        ;
	 *   0               ,  0                   。
	 * @return         
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object clone(Object value,int level) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
		if(value==null){
			return null;
		}
		if(level==0){
			return value;
		}
		Class c = value.getClass();
		if(isNeedlessClone(c)){
			return value;
		}
		level--;
		if(value instanceof Collection){//      
			Collection tmp = (Collection)c.newInstance();
			for(Object v:(Collection)value){
				tmp.add(clone(v,level));//    
			}
			value = tmp;
		}
		else if(c.isArray()){//    Array
			//             
			if(c.equals(int[].class)){
				int[] old = (int[])value;
				value = (int[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(short[].class)){
				short[] old = (short[])value;
				value = (short[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(char[].class)){
				char[] old = (char[])value;
				value = (char[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(float[].class)){
				float[] old = (float[])value;
				value = (float[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(double[].class)){
				double[] old = (double[])value;
				value = (double[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(long[].class)){
				long[] old = (long[])value;
				value = (long[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(boolean[].class)){
				boolean[] old = (boolean[])value;
				value = (boolean[])Arrays.copyOf(old, old.length);
			}
			else if(c.equals(byte[].class)){
				byte[] old = (byte[])value;
				value = (byte[])Arrays.copyOf(old, old.length);
			}
			else {
				Object[] old = (Object[])value;
				Object[] tmp = (Object[])Arrays.copyOf(old, old.length, old.getClass());
				for(int i = 0;i<old.length;i++){
					tmp[i] = clone(old[i],level);
				}
				value = tmp;
			}
		}
		else if(value instanceof Map){//    MAP
			Map tmp = (Map)c.newInstance();
			Map org = (Map)value;
			for(Object key:org.keySet()){
				tmp.put(key, clone(org.get(key),level));//    
			}
			value = tmp;
		}
		else {
			Object tmp = createObject(value);
			if(tmp==null){//              ,    
				return value;
			}
			Set<Field> fields = new HashSet<Field>();
			while(c!=null&&!c.equals(Object.class)){
				fields.addAll(Arrays.asList(c.getDeclaredFields()));
				c = c.getSuperclass();
			}
			for(Field field:fields){
				if(!Modifier.isFinal(field.getModifiers())){//    final  
					field.setAccessible(true);
					field.set(tmp, clone(field.get(value),level));//    
				}
			}
			value = tmp;
		}
		return value;
	}
	
	/**
	 *       
	 * @param value     
	 * @return       ,     
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object clone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
		return clone(value,1);
	}
	
	/**
	 *       
	 * @param value     
	 * @return       
	 * @throws IllegalAccessException
	 * @throws InstantiationException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object deepClone(Object value) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException{
		return clone(value,-1);
	}
}


注意:このレプリケーション・メソッドは安全ではありません.finalフィールドや空のない構造メソッドのタイプなど、特定の場合は値をレプリケーションできません.通常のDTO、POJOなどのレプリケーションにのみ適用されます.その他の場合は注意してください.