1.问题描述
今天在一个java学习群里偶然看到一段代码,如下所示。public static void main(String[] args) { int data [][] ={{1,2,3},{4,5,6},{7,8,9}}; int dataTest[][]; dataTest = Arrays.copyOf(data, data.length); dataTest[0][0] = data[2][2]; for (int i = 0; i < data.length; i++) { System.out.println(Arrays.toString(data[i])); } }
问题的发起人提出了疑问,打印结果是什么,为什么会这样?原理是什么。一开始我简单看了下,没弄清楚他要问的具体是什么。简单看了下,不就是复制了个二维数组,然后修改了下元素值嘛。但是他的意思却是,为什么明明修改的是dataTest里的值,但是打印data里元素时也发生了改变?这段代码的运行结果如下图:一时间,我也没反应过来,陷入了思维误区,然后想来想去,难不成是Arrays.copyOf这个方法的问题?于是就去翻看了Arrays.copyOf的源码。2.解决过程
于是我按照源码,将这个案例改写了如下所示public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }源码的大概意思是:先取得数组的Class对象,判断这个数组是否是Object类型的数组,如果是的话就创建个新的Object类型的数组,否则的话调用newInstance方法创建相同类型的数组。然后调用System.arrayCopy方法将原数组中的元素复制到新的数组中,并最终返回。public static void main(String[] args) { int data [][] ={{1,2,3},{4,5,6},{7,8,9}}; int copy[][]; System.out.println((Object)data.getClass() == (Object)Object[].class); copy = (int[][]) Array.newInstance(data.getClass().getComponentType(), 3); System.arraycopy(data, 0, copy, 0,Math.min(data.length, 3)); for (int i = 0; i < data.length; i++) { System.out.println(Arrays.toString(data[i])); } }所以说,其实两个二维数组只是本身的地址值不一样,但是其中的元素是一样的。之所以会出现上面的思维误区,是因为忘了二维数组中存放的是一维数组的引用。画个简单的内存图来看:
调用dataTest[0][0]=data[2][2],其实是修改了0x101数组中的元素值。data和dataTest中第一个元素指向的都是0x101这块区域。所以最终打印data数组,值也发生了改变,出现了上述的思维误区。3.总结
其实出这个问题的最主要原因还是没搞清楚二维数组中存放的是每个一维数组的引用,而不是具体的元素值。不过通过这次小问题也看了看Arrays类中copyOf方法的源码,也算有一些收获。有时候学习就会陷入一种误区,知识点一综合,感觉被新的方法、新的技术绕进去了,但仔细想想,问题的本质出在哪儿,可能就是你忽略了的基础而已。。


2万+





