方案1:新建数组 这种方法新建的数组必须要比原先的长度要长,然后将原来的数组内容移到新的数组中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int [] a = {1 , 2 , 3 , 4 , 5 };int [] b = new int [a.length * 2 ];for (int i = 0 ; i < a.length; i++) { b[i] = a[i]; } a = b; System.out.println(Arrays.toString(a));
输出结果
1 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
方案2:Arrays.copyOf 1 2 3 4 5 6 7 int [] a = {1 , 2 , 3 , 4 , 5 };a = Arrays.copyOf(a, a.length * 2 ); System.out.println(Arrays.toString(a));
输出结果
1 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
Arrays.copyof是用于数组进行复制时常使用的方法,本身在Arrays类里面,而之所以能这么使用而不用创建对象在于该方法本身由static修饰,被static修饰的方法可以在该类创建对象前载入jvm。
1 2 3 4 5 6 public static long[] copyOf(long[] original, int newLength) { long[] copy = new long[newLength]; System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
通过上面的代码可以看出,其本质是调用了System.arraycopy方法。
先产生一个新的数组然后调用arraycopy方法最后在返回产生的新数组。但是我们进行数组扩容的时候禅城了新数组,但是原数组依然存在,造成了内存的浪费。
方案3:System.arraycopy 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 int[] a = {1, 2, 3, 4, 5}; // 定义新数组,长度为源数组的两倍 int[] b = new int[a.length * 2]; /** * src 需要拷贝的源数组 * srcPos 源数组中的起始位置 * dest 目标数组 * destPos 目标数组中的起始位置 * length 要复制的数组元素数量 */ System.arraycopy(a, 0, b, 0, a.length); // 新数组内容赋值给原数组 a = b; // 打印结果 System.out.println(Arrays.toString(a));
输出结果
1 [1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
arraycopy源码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public static native void arraycopy (Object src, int srcPos, Object dest, int destPos, int length) ;
System.arraycopy()的几种常用方法(普通for循环和arraycopy方法对比) 1. 从旧数组拷贝到新数组 1 2 3 4 5 //从旧数组拷贝到新数组 for (int i=0;i<size;i++){ arrayNew[i]=array[i]; } System.arraycopy(array, 0, arrayNew, 0, array.length);
2. 从左向右循环,逐个元素向左挪一位。 1 2 3 4 5 //从左向右循环,逐个元素向左挪一位。 for (int i = index; i < size - 1; i++) { array[i] = array[i + 1]; } System.arraycopy(array, index + 1, array, index, size - 1 - index);
3. 从右向左循环,逐个元素向右挪一位。 1 2 3 4 5 6 //从右向左循环,逐个元素向右挪一位。 for (int i = size - 1; i >= index; i--) { array[i + 1] = array[i]; } System.arraycopy(array, index, array, index + 1, size - index);
System.arraycopy()深层理解 深复制还是浅复制 1 2 3 先说结论 : 当数组为一维数组,且元素为基本类型或String类型时,属于深拷贝,即原数组与新数组的元素不会相互影响。 当数组为多维数组,或一维数组中的元素为引用类型时,属于浅拷贝,原数组与新数组的元素引用指向同一个对象。
引用对象 构建一个User类型源数组,复制后至target数组,比较第一个元素的内存地址,判断结果是相同的,证明为浅复制
;后修改target数组数组的随机元素,发现原来的值也变了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class SystemArrayCopyTestCase { public static void main(String[] args) { User[] users = new User[] { new User(1), new User(2), new User(3) };// 初始化对象数组 User[] target = new User[users.length];// 新建一个目标对象数组 System.arraycopy(users, 0, target, 0, users.length);// 实现复制 System.out.println("源对象与目标对象的物理地址是否一样:" + (users[0] == target[0] ? "浅复制" : "深复制")); //浅复制 target[0].setId(5); System.out.println("修改目标对象的属性值后源对象users:"); for (User user : users) { System.out.println(user); } } } class User { }
System.arraycopy() 在拷贝数组的时候,采用的使用潜复制,复制结果是一维的引用变量传递给新数组的一维数组 ,修改新数组时,会影响原来的数组。
一维数组和多维数组 将一维数组作源数组,进行拷贝,产生target数组;然后修改target数组中的元素,新数组没变,证明是值拷贝,修改新数组不会影响原来的值。
将多维数组作源数组,进行拷贝至目标数组,修改至目标数组的元素,新数组也变了,说明是二者是相同的引用,而这时改变其中任何一个数组的元素的值,其实都修改了共同数组元素的值,所以原数组和新数组的元素值都一样了
线程是否安全(摘自网络) System.ayyaycopy是不安全的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public class ArrayCopyThreadSafe { private static int[] arrayOriginal = new int[1024 * 1024 * 10]; private static int[] arraySrc = new int[1024 * 1024 * 10]; private static int[] arrayDist = new int[1024 * 1024 * 10]; private static ReentrantLock lock = new ReentrantLock(); private static void modify() { for (int i = 0; i < arraySrc.length; i++) { arraySrc[i] = i + 1; } } private static void copy() { System.arraycopy(arraySrc, 0, arrayDist, 0, arraySrc.length); } private static void init() { for (int i = 0; i < arraySrc.length; i++) { arrayOriginal[i] = i; arraySrc[i] = i; arrayDist[i] = 0; } } private static void doThreadSafeCheck() throws Exception { for (int i = 0; i < 100; i++) { System.out.println("run count: " + (i + 1)); init(); Condition condition = lock.newCondition(); new Thread(new Runnable() { @Override public void run() { lock.lock(); condition.signalAll(); lock.unlock(); copy(); } }).start(); lock.lock(); // 这里使用 Condition 来保证拷贝线程先已经运行了. condition.await(); lock.unlock(); Thread.sleep(2); // 休眠2毫秒, 确保拷贝操作已经执行了, 才执行修改操作. modify(); if (!Arrays.equals(arrayOriginal, arrayDist)) { throw new RuntimeException("System.arraycopy is not thread safe"); } } } public static void main(String[] args) throws Exception { doThreadSafeCheck(); } }
这个例子的具体操作是:
arrayOriginal 和 arraySrc 初始化时是相同的, 而 arrayDist 是全为零的.
启动一个线程运行 copy() 方法来拷贝 arraySrc 到 arrayDist 中.
在主线程执行 modify() 操作, 修改 arraySrc 的内容. 为了确保 copy() 操作先于 modify() 操作, 我使用 Condition, 并且延时了两毫秒, 以此来保证执行拷贝操作(即System.arraycopy) 先于修改操作.
根据第三点, 如果 System.arraycopy 是线程安全的, 那么先执行拷贝操作, 再执行修改操作时, 不会影响复制结果, 因此 arrayOriginal 必然等于 arrayDist; 而如果 System.arraycopy 是线程不安全的, 那么 arrayOriginal 不等于 arrayDist.
1 2 3 4 5 run count: 1 Exception in thread "main" java.lang.RuntimeException: System.arraycopy is not thread safe at ArrayCopyThreadSafe.doThreadSafeCheck(ArrayCopyThreadSafe.java:54) at ArrayCopyThreadSafe.main(ArrayCopyThreadSafe.java:60)
结论 :System.ayyaycopy是不安全的。
System.arraycopy()和for()相比谁更高效 当测试数组的范围比较小的时候,两者相差的时间无几,当测试数组的长度达到百万级别,System.arraycopy的速度优势就开始体现了,根据对底层的理解,System.arraycopy是对内存直接进行复制,减少了for循环过程中的寻址时间,从而提高了效能。
如果有帮助到你的话,请关注我的公众号叭
CSDN 白.都