Java中的陣列拷貝以及物件Bean拷貝
陣列拷貝方式
直接先貼出測試程式碼:
Student :
package com.tonglei.test;
/**
* 學生實體測試類
*
* @author ffj
*
*/
public class Student {
private int age;
private int height;
private String sex;
public Student(int age, int height, String sex) {
this.age = age;
this.height = height;
this .sex = sex;
}
// 省略set、get方法
@Override
public String toString() {
return "Student :[" + this.age + " ," + this.height + " ," + this.sex + "]";
}
}
執行測試 :
public static void main(String[] args) {
Student[] stu = new Student[3];
stu[0] = new Student(11 , 110, "男");
stu[1] = new Student(12, 120, "女");
stu[2] = new Student(13, 130, "嬲");
System.out.println("stu length :" + stu.length);
System.out.println("stu :" + Arrays.toString(stu));
System.out.println("stu address :" + stu);
System.out.println("<------------------------------------->" );
// Arrays.copyOf 原陣列 新陣列長度
Student[] arrayCopyStu = Arrays.copyOf(stu, stu.length + 1);
arrayCopyStu[stu.length] = new Student(14, 140, "奻");
System.out.println("arrayCopyStu length :" + arrayCopyStu.length);
System.out.println("arrayCopyStu :" + Arrays.toString(arrayCopyStu));
System.out.println("arrayCopyStu address :" + arrayCopyStu);
System.out.println("<------------------------------------->");
// System.arraycopy 原陣列 原陣列拷貝起始地址 目標陣列 目標陣列拷貝起始地址 拷貝長度
Student[] systemCopyStu = new Student[4];
System.arraycopy(stu, 0, systemCopyStu, 0, stu.length);
System.out.println("systemCopyStu length :" + systemCopyStu.length);
System.out.println("systemCopyStu :" + Arrays.toString(systemCopyStu));
System.out.println("systemCopyStu address :" + systemCopyStu);
System.out.println("<------------------------------------->");
System.out.println("<---------改變了原陣列第一個物件的age------->");
System.out.println("<------------------------------------->");
// 改變原陣列的資料
stu[0].setAge(99);
System.out.println("stu :" + Arrays.toString(stu));
System.out.println("arrayCopyStu :" + Arrays.toString(arrayCopyStu));
System.out.println("systemCopyStu :" + Arrays.toString(systemCopyStu));
/**
* 總結:Arrays.copyOf 和 System.arraycopy 都可將結果生成一個新陣列,
* 不過兩者的區別在於,Arrays.copyOf()不僅僅只是拷貝陣列中的元素,在拷貝元素時,會建立一個新的陣列物件。而System.arrayCopy只拷貝已經存在陣列元素。
* Arrays.copyOf()的原始碼中可知其底層還是呼叫了System.arrayCopyOf()方法
* 當修改了原陣列中物件的屬性時目標陣列中也隨之改變,故兩者都是地址引用,其中元素指向的還是原陣列的地址
*/
}
測試執行結果 :
stu length :3
stu :[Student :[11 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲]]
stu address :[Lcom.tonglei.test.Student;@70dea4e
<------------------------------------->
arrayCopyStu length :4
arrayCopyStu :[Student :[11 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], Student :[14 ,140 ,奻]]
arrayCopyStu address :[Lcom.tonglei.test.Student;@5c647e05
<------------------------------------->
systemCopyStu length :4
systemCopyStu :[Student :[11 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], null]
systemCopyStu address :[Lcom.tonglei.test.Student;@33909752
<------------------------------------->
<---------改變了原陣列第一個物件的age------->
<------------------------------------->
stu :[Student :[99 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲]]
arrayCopyStu :[Student :[99 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], Student :[14 ,140 ,奻]]
systemCopyStu :[Student :[99 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], null]
Arrays.copyOf
Arrays.copyOf
方法返回一個新陣列,不僅僅只是拷貝原陣列中的元素會建立一個新的陣列物件
上述測試結果 :
<------------------------------------->
arrayCopyStu length :4
arrayCopyStu :[Student :[11 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], Student :[14 ,140 ,奻]]
arrayCopyStu address :[Lcom.tonglei.test.Student;@5c647e05
<------------------------------------->
可以看出,copy原陣列中元素並擴容了一長度,同時arrayCopyStu[stu.length] = new Student(14, 140, "奻");
對新增元素賦值,從而打印出的便是上述內容。
System.arraycopy
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
方法只拷貝已經存在陣列元素,引數依次為原陣列、原陣列拷貝起始地址、目標陣列、目標陣列拷貝起始地址、拷貝長度。
上述測試結果 :
<------------------------------------->
systemCopyStu length :4
systemCopyStu :[Student :[11 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], null]
systemCopyStu address :[Lcom.tonglei.test.Student;@33909752
<------------------------------------->
可見,新陣列只從原陣列中拷貝了存在的指定個數元素並可以指定拷貝到目標陣列中。
從Arrays.copyOf()
的原始碼中可知其底層還是呼叫了System.arrayCopyOf()
方法。
進而探究
兩種均可對陣列進行copy,但是Arrays.copyOf()
和System.arrayCopyOf()
兩種方法所copy生成的新的陣列物件中的元素物件到底是新的還是依舊指向原先的呢?來一探究竟!
然而細心的同學已經心領神會..測試程式碼早早貼在了上面!
System.out.println("<------------------------------------->");
System.out.println("<---------改變了原陣列第一個物件的age------->");
System.out.println("<------------------------------------->");
// 改變原陣列的資料
stu[0].setAge(99);
System.out.println("stu :" + Arrays.toString(stu));
System.out.println("arrayCopyStu :" + Arrays.toString(arrayCopyStu));
System.out.println("systemCopyStu :" + Arrays.toString(systemCopyStu));
這段程式碼我改變了原陣列中第一個stu物件元素中的age屬性值,我將其改為了99。
結果顯示為 :
<------------------------------------->
<---------改變了原陣列第一個物件的age------->
<------------------------------------->
stu :[Student :[99 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲]]
arrayCopyStu :[Student :[99 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], Student :[14 ,140 ,奻]]
systemCopyStu :[Student :[99 ,110 ,男], Student :[12 ,120 ,女], Student :[13 ,130 ,嬲], null]
顯而易見了,不管是原陣列還是兩個copy的陣列,其值均由原先的11變成了99。
總結:當修改了原陣列中物件的屬性時目標陣列中也隨之改變,故兩者都是地址引用,其中元素指向的還是原陣列的地址。
物件拷貝方式
測試類還是上面的Student
,只不過我又新增了一個Teacher
類來方便測試,其結構與Student
一致。
Teacher :
package com.tonglei.test;
/**
* 教師實體測試類
*
* @author ffj
*
*/
public class Teacher {
private int age;
private int height;
private String sex;
public Teacher() {
}
public Teacher(int age, int height, String sex) {
this.age = age;
this.height = height;
this.sex = sex;
}
// 省略了set、get方法
@Override
public String toString() {
return "Teacher :[" + this.age + " ," + this.height + " ," + this.sex + "]";
}
}
測試的初始程式碼 :
Student stu = new Student(18, 180, "男");
Teacher tea = new Teacher();
SpringBeanUtils
BeanUtils.copyProperties(Object source, Object target)
該方法為spring中方法,故需要匯入相應jar包。引數依次為:源陣列、目標陣列。(方法間引數有差異,需注意!)
測試程式碼 :
BeanUtils.copyProperties(stu, tea);
System.out.println(tea);
在執行測試之前,我先將原先Teacher
中的age
欄位屬性型別稍稍修改了下。改為了private String age
,結果為Could not copy properties from source to target; nested exception is java.lang.IllegalArgumentException
,拋了個異常錯誤。而後我將其型別改回,輸出Teacher :[18 ,180 ,男]
。故:拷貝的目標陣列與源陣列中的元素物件其屬性名稱一樣,型別就必須一致,否則會報錯
commonsBeanUtils
該包下有兩個copy方法:BeanUtils.copyProperties(Object dest, Object orig)
和PropertyUtils.copyProperties(Object dest, Object orig)
,同樣使用其方法前需要匯入對應org.apache.commons
jar包。
BeanUtils.copyProperties
BeanUtils.copyProperties(Object dest, Object orig)
其中引數分別為:目標陣列、源陣列。(對了,跟spring中方法引數順序不一樣)
測試程式碼 :
System.out.println(stu);
org.apache.commons.beanutils.BeanUtils.copyProperties(tea, stu);
System.out.println(tea);
還是老步驟:在執行測試之前,我先將原先Teacher
中的age
欄位屬性型別稍稍修改了下。改為了private String age
,結果顯示為:
Student :[18 ,180 ,男]
Teacher :[18 ,180 ,男]
我再將Teacher
中的sex
欄位改為了private int sex
,結果顯示為:
Student :[18 ,180 ,男]
Teacher :[18 ,180 ,0]
由此可知:拷貝的目標陣列與源陣列中的元素物件其屬性名稱一樣,型別不一致則會強轉該值,若是強轉不了就為初始值
PropertyUtils.copyProperties
PropertyUtils.copyProperties(Object dest, Object orig)
其中引數分別為:目標陣列、源陣列。
測試程式碼 :
System.out.println(stu);
PropertyUtils.copyProperties(tea, stu);
System.out.println(tea);
一樣,在執行測試之前,我先將原先Teacher
中的age
欄位屬性型別稍稍修改了下。改為了private String age
,結果顯示為:Cannot invoke com.tonglei.test.Teacher.setAge on bean class 'class com.tonglei.test.Teacher' - argument type mismatch - had objects of type "java.lang.Integer" but expected signature "java.lang.String"
,報錯丟擲型別不匹配異常資訊,再將型別改回,輸出:
Student :[18 ,180 ,男]
Teacher :[18 ,180 ,男]
故:拷貝的目標陣列與源陣列中的元素物件其屬性名稱一樣,型別就必須一致,否則會報錯(與SpringBeanUtils差不多不過報錯資訊更為詳細,純粹這次簡單測試個人體會)
參考博文
具體方法具體場景各自選擇。 END.