因为在看集合源码的时候经常会看到这两个方法,以前也没怎么接触过,导致傻傻分不清楚,这里正好记录下
1.System.arraycopy()
该方法是本地方法
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
src - 被复制的数组
srcPos - 源数组要被复制的起始位置
dest - 目标数组
destPos - 目标数组放置的起始位置
length - 数组复制的长度
举个例子
public class Student {
private String name;
private String sex;
private String email;
public Student(String name, String sex, String email) {
this.name = name;
this.sex = sex;
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
", email='" + email + '\'' +
'}';
}
@Test
public void arrayOfTest() {
Student[] students = new Student[] {
new Student("CCC","male","AAA@126.com"),
new Student("BBB","female","BBB@126.com"),
new Student("AAA","female","CCC@126.com"),
};
Student[] target = new Student[students.length];
System.arraycopy(students,0, target,0,students.length);
target[0].setName("LWH");
System.out.println("修改目标对象属性值后的原对象:");
for (Student stu: students){
System.out.println(stu);
}
}
}
结果:
修改目标对象属性值后的原对象:
Student{name='LWH', sex='male', email='AAA@126.com'}
Student{name='BBB', sex='female', email='BBB@126.com'}
Student{name='AAA', sex='female', email='CCC@126.com'}
修改目标对象属性值后得对象:
Student{name='LWH', sex='male', email='AAA@126.com'}
Student{name='BBB', sex='female', email='BBB@126.com'}
Student{name='AAA', sex='female', email='CCC@126.com'}
改变前后 Student 中得属性值都发生了改变,可见 System.arraycopy 方法实现了浅拷贝,即对引用数据类型进行引用般的传递
2.Arrays.copyof()
public static <T> T[] copyOf(T[] original,
int newLength)
original:要被复制的数组
newLength:需要被复制的数组的长度
源码分析
因为 Arrays 里面有很多 copyof 的重载方法,其实本质都是一样的,底层都是调用 System.arraycopy 本地方法,然后返回复制后的数组。这里我就列举一个 int 类型的和一个泛型类的
// 传入 int 类型的数组
public static int[] copyOf(int[] original, int newLength) {
// 创建一个已经初始化后的新数组,用于存放复制后的数组
int[] copy = new int[newLength];
// 将参数中传入的数组复制到新创建的数组中
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
//返回复制后的数组
return copy;
}
// 传入泛型类的数组
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
// 判断传入的参数组参数是否是 Object 类的
T[] copy = ((Object)newType == (Object)Object[].class)
// 如果是,则直接初始化一个 Object 类的数组
? (T[]) new Object[newLength]
// 如果不是,则直接转换为传入的参数类型后在对数组进行初始化
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
//返回复制后的数组
return copy;
}
举个例子
@Test
public void copyofTest() {
Student[] students = new Student[] {
new Student("CCC","male","AAA@126.com"),
new Student("BBB","female","BBB@126.com"),
new Student("AAA","female","CCC@126.com"),
};
Student[] students1 = Arrays.copyOf(students, 3);
students1[0].setName("LWH");
System.out.println("修改目标对象属性值后的原对象:");
for (Student stu: students1) {
System.out.println(stu);
}
System.out.println("修改目标对象属性值后得对象:");
for(Student stu: students) {
System.out.println(stu);
}
}
结果:
修改目标对象属性值后的原对象:
Student{name='LWH', sex='male', email='AAA@126.com'}
Student{name='BBB', sex='female', email='BBB@126.com'}
Student{name='AAA', sex='female', email='CCC@126.com'}
修改目标对象属性值后得对象:
Student{name='LWH', sex='male', email='AAA@126.com'}
Student{name='BBB', sex='female', email='BBB@126.com'}
Student{name='AAA', sex='female', email='CCC@126.com'}
结果和 System.arraycopy 方法一样,毕竟底层调用的就是 System.arrcopy 嘛,其实本质是一样的,也是浅拷贝
3.总结
System.arraycopy
- 该方法需要自己定义一个目标数组,同时可以自己定制复制的内容,即从被复制数组的哪个位置开始,复制到目标数组的哪个位置,可以选择复制的长度
- 适用于数组的元素的前后移动,如插入,删除等等
- 该方法的复制是浅拷贝
Arrays.copyof
- 方法可以看作是精简版的 System.arraycopy 数组,因为不需要自己定义目标数组,而且只能从被复制数组的头部复制目标数组的头部,可以选择复制的长度
- 它主要是用来将原数组全部拷贝到一个新长度的数组,适用于数组扩容
- 该方法的复制是浅拷贝
4.参考
https://segmentfault.com/a/1190000009922279
https://www.jianshu.com/p/840976f14950