System.arraycopy详解

一、前言

对数组的复制,有四种方法:
for
clone
System.arraycopy
arrays.copyof
下面分析一下最常用的System.arraycopy()

二、源码拜读

1、源码

2、参数分析
Object src : 原数组
int srcPos : 从元数据的起始位置开始
Object dest : 目标数组
int destPos : 目标数组的开始起始位置
int length : 要copy的数组的长度

三、深拷贝与浅拷贝

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。
1、简单类型(深拷贝)
package com.guor.test.javaSE.collection;
import java.util.Arrays;
public class ArrayTest {}
只有普通数据类型和String类型是深拷贝!

public static void main(String[] args) {
	getStringArrayFromObjectArray2();
}

private static void copySelf() {
	int[] ids = { 1, 2, 3, 4, 5 };  
	System.out.println(Arrays.toString(ids));
	//System.arraycopy(src, srcPos, dest, destPos, length);
	// 把从索引0开始的2个数字复制到索引为3的位置上  
	System.arraycopy(ids, 0, ids, 3, 2);
	System.out.println(Arrays.toString(ids));//[1, 2, 3, 1, 2]
}

private static void copyToOther() {
	int[] ids = { 1, 2, 3, 4, 5 };  
	//将数据的索引1开始的3个数据复制到目标的索引为0的位置上  
	int[] other = new int[5];
	System.arraycopy(ids, 1, other, 0, 3);
	System.out.println(Arrays.toString(ids));//[1, 2, 3, 4, 5]深复制
	System.out.println(Arrays.toString(other));//[2, 3, 4, 0, 0]
}

//如果是类型转换问题,获取整形
private static void getIntegerArrayFromObjectArray() {
	Object[] obj1 = { 1, 2, 3, "4", "5" }; 
	Integer[] obj2 = new Integer[5];
	
	try {
		System.arraycopy(obj1, 0, obj2, 0, obj1.length);
	} catch (Exception e) {
		System.out.println("transfer exception:"+e);
	}
	System.out.println(Arrays.toString(obj1));
	System.out.println(Arrays.toString(obj2));
}

//获取Object数组中的字符串类型数据
private static void getStringArrayFromObjectArray1() {
	Object[] obj3 = { 1, 2, 3, "4", "5" }; 
	String[] obj4 = new String[5];
	try {
		System.arraycopy(obj3, 2, obj4, 2, 3);
	} catch (Exception e) {
		//transfer exception:java.lang.ArrayStoreException
		System.out.println("transfer exception:"+e);
	}
	System.out.println(Arrays.toString(obj3));
	//[null, null, null, null, null]
	System.out.println(Arrays.toString(obj4));
}

//获取Object数组中的字符串类型数据
private static void getStringArrayFromObjectArray2() {
	Object[] obj3 = { 1, 2, 3, "4", "5" }; 
	String[] obj4 = new String[5];
	try {
		System.arraycopy(obj3, 3, obj4, 3, 2);
	} catch (Exception e) {
		System.out.println("transfer exception:"+e);
	}
	System.out.println(Arrays.toString(obj3));
	//[null, null, null, 4, 5]
	System.out.println(Arrays.toString(obj4));
	obj3[3] = "zhangssan";
	System.out.println("查看是浅复制还是深复制~~~~~");
	System.out.println(Arrays.toString(obj3));
	System.out.println(Arrays.toString(obj4));
}

2、二维数组(浅拷贝)
//二维数组
public static void twoArray() {
int[] arr1 = {1, 2};
int[] arr2 = {3, 4};
int[] arr3 = {5, 6};
}

//二维数组toString()
private static void print(String string, int[][] arr) {
System.out.print(string);
for (int[] a : arr) {
for (int i : a) {
System.out.print(i + " “);
}
System.out.print(”,");
}
System.out.println();
}
二维数组属于浅拷贝,原始数组改变后,复制的数据也发生了改变!

int[][] src = new int[][]{arr1, arr2, arr3};

print("原始模样:", src);
int[][] dest = new int[3][];
System.arraycopy(src, 0, dest, 0, 3);

System.out.println("改变前");
print("src = ", src);
print("dest = ", dest);

//原数组改变后观察新数组是否改变,改变->浅复制,不改变->深复制
src[0][0] = -1;

System.out.println("改变后");
print("src = ", src);
print("dest = ", dest);

3、对象复制(深拷贝?)

四、System.arraycopy是不安全的

1、代码实例
多线程对数组进行复制,看System.arraycopy线程是否安全?

package com.guor.test.javaSE.collection;

import java.util.Arrays;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ArrayTest2 {
private static int[] arrayOriginal = new int[1024 * 1024 * 10];
private static int[] arraySrc = new int[1024 * 1024 * 10];
private static int[] arrayDest = 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, arrayDest, 0, arraySrc.length);
}

private static void init() {
    for (int i = 0; i < arraySrc.length; i++) {
        arrayOriginal[i] = i;
        arraySrc[i] = i;
        arrayDest[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();

        // 如果 System.arraycopy 是线程安全的, 那么先执行拷贝操作, 再执行修改操作时, 不会影响复制结果, 因此 arrayOriginal 必然等于 arrayDist; 
        if (!Arrays.equals(arrayOriginal, arrayDest)) {
            throw new RuntimeException("System.arraycopy is not thread safe");
        }
    }
}

public static void main(String[] args) throws Exception {
    //doThreadSafeCheck();
    executeTime();
}

private static void executeTime() {
	String[] srcArray = new String[1000000];
    String[] forArray = new String[srcArray.length];
    String[] arrayCopyArray  = new String[srcArray.length];
    
    //初始化数组
    for(int i  = 0 ; i  < srcArray.length ; i ++){
        srcArray[i] = String.valueOf(i);
    }
    
    long forStartTime = System.currentTimeMillis();
    for(int index  = 0 ; index  < srcArray.length ; index ++){
        forArray[index] = srcArray[index];
    }
    long forEndTime = System.currentTimeMillis();
    System.out.println("for方式复制数组:"  + (forEndTime - forStartTime));
    
    long arrayCopyStartTime = System.currentTimeMillis();
    System.arraycopy(srcArray,0,arrayCopyArray,0,srcArray.length);
    long arrayCopyEndTime = System.currentTimeMillis();
    System.out.println("System.arraycopy复制数组:"  + (arrayCopyEndTime - arrayCopyStartTime));
}

2、代码思路分析
arrayOriginal 和 arraySrc 初始化时是相同的, 而 arrayDist 是全为零的.

启动一个线程运行 copy() 方法来拷贝 arraySrc 到 arrayDist 中.

在主线程执行 modify() 操作, 修改 arraySrc 的内容. 为了确保 copy() 操作先于 modify() 操作, 我使用 Condition, 并且延时了两毫秒, 以此来保证执行拷贝操作(即System.arraycopy) 先于修改操作.

根据第三点, 如果 System.arraycopy 是线程安全的, 那么先执行拷贝操作, 再执行修改操作时, 不会影响复制结果, 因此 arrayOriginal 必然等于 arrayDist; 而如果 System.arraycopy 是线程不安全的, 那么 arrayOriginal 不等于 arrayDist.

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
System.arraycopyJava中的一个方法,用于将一个数组的内容复制到另一个数组中。它的用法是:System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)。其中,src是源数组,srcPos是源数组的起始位置,dest是目标数组,destPos是目标数组的起始位置,length是要复制的元素个数。 System.arraycopy是一种浅拷贝方式,它只是将源数组的引用复制给目标数组,而不会复制源数组中的元素的值。因此,如果原始数组改变了,复制的数组也会发生相应的改变。 关于System.arraycopy的具体实现,可以参考引用中的源码拜读部分。另外,引用中也提到了System.arraycopy是对数组进行复制的常用方法。 在引用的代码示例中,可以看到System.arraycopy的具体用法。首先定义了一个二维数组src,然后使用System.arraycopy将src复制给了dest数组。接着,通过修改src数组的元素,可以观察到dest数组也发生了相应的改变,这正是浅拷贝的特性。 总之,System.arraycopyJava中用于数组复制的方法,它是一种浅拷贝方式,可以将源数组的内容复制到目标数组中。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [System.arraycopy详解](https://blog.csdn.net/yangruidage21/article/details/128519021)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值