JDK-8173962 : Add API for Deep copy of multi-dimensional arrays
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 8,9
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2017-02-04
  • Updated: 2017-03-01
Related Reports
Relates :  
Relates :  
Description
A DESCRIPTION OF THE REQUEST :
In the class Arrays of the package java.util there isn't a method that allows deep copy of multiarrays.

JUSTIFICATION :
This enhancement is necessary for coping a multiarray that should be assigned to a field or returned by a getter method, to ensure that the data structure will not be modified externally of the class.


---------- BEGIN SOURCE ----------
import java.util.Arrays;

public class Test {
	public static void main(String[] args) {
		int[][] array1=new int[2][2];
		//the Arrays.copyOf and array1.clone methods perform a shallow copy of array1
		int[][] array2=Arrays.copyOf(array1, array1.length);
		int[][] array3=array1.clone();
		
		//array1, array2, array3 are different arrays because their internal addresses aren't equal
		System.out.println("Internal address of array1: "+System.identityHashCode(array1));
		System.out.println("Internal address of array2: "+System.identityHashCode(array2));
		System.out.println("Internal address of array3: "+System.identityHashCode(array3));
		System.out.println();
		
		//elements of array1, array2, array3 are the same because they have equal internal addresses
		System.out.println("Element's internal addresses of array1:");
		for(int i=0;i<array1.length;i++)
			System.out.println(System.identityHashCode(array1[i]));
		System.out.println("Element's internal addresses of array2:");
		for(int i=0;i<array2.length;i++)
			System.out.println(System.identityHashCode(array2[i]));
		System.out.println("Element's internal addresses of array3:");
		for(int i=0;i<array3.length;i++)
			System.out.println(System.identityHashCode(array3[i]));
		
		System.out.println();
		//the modifications performed on an array are reflected on the others
		array1[0][0]=1;
		System.out.println("array1[0][0]=1;");
		System.out.println("array1:\n"+Arrays.deepToString(array1));
		System.out.println("array2:\n"+Arrays.deepToString(array2));
		System.out.println("array3:\n"+Arrays.deepToString(array3));
		System.out.println();
		array2[0][1]=2;
		System.out.println("array2[0][1]=2;");
		System.out.println("array1:\n"+Arrays.deepToString(array1));
		System.out.println("array2:\n"+Arrays.deepToString(array2));
		System.out.println("array3:\n"+Arrays.deepToString(array3));
		System.out.println();
		array3[1][0]=3;
		System.out.println("array3[1][0]=3;");
		System.out.println("array1:\n"+Arrays.deepToString(array1));
		System.out.println("array2:\n"+Arrays.deepToString(array2));
		System.out.println("array3:\n"+Arrays.deepToString(array3));
		System.out.println();
	}
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
import java.lang.reflect.Array;
import java.util.HashMap;

public class Utils {
	
	public static <T> T[] deepCopyOf(T[] array){
		return deepCopyOf(array, new HashMap<>());
	}
	
	@SuppressWarnings("unchecked")
	private static <T> T deepCopyOf(T array, HashMap<Object, Object> dejavu){
		T copy=(T) dejavu.get(array);
		
		if(copy==null){
			Class<?> componentType=array.getClass().getComponentType();
			int length=Array.getLength(array);
			copy=(T) Array.newInstance(componentType, length);
			boolean multiarray=componentType.isArray();
			dejavu.put(array, copy);
			
			if(multiarray || componentType==Object.class){
				Object[] src=(Object[]) array, dest=(Object[]) copy;
				
				if(multiarray){
					for(int i=0;i<length;i++){
						Object o=src[i];
						dest[i]=(o!=null) ? deepCopyOf(o, dejavu) : null;
					}
				}else{
					for(int i=0;i<length;i++){
						Object o=src[i];
						dest[i]=(o!=null && o.getClass().isArray()) ? deepCopyOf(o, dejavu) : o;
					}
				}
			}else
				System.arraycopy(array, 0, copy, 0, length);
		}
		
		return copy;
	}
}


Comments
Might be useful for primitive arrays. A deep copy of multi-dimensional arrays containing objects of reference types is ill-defined, as there's no way in general to do a deep copy of an arbitrary object. Coming with a type-safe signature for a arbitrary-dimension array of primitives is a challenge. It might have to be Object, and then have the check occur at runtime. A variation is to do a multi-D deep copy and to let the caller pass a copying function (UnaryOperator<T>) for the base component type of the array. This would also have a type-unsafe signature and have to be checked at runtime. This seems fairly dubious, though. It might work if the array base component type were Copyable, per JDK-5101827.
07-02-2017