天天看點

Java中的數組拷貝以及對象Bean拷貝

個人部落格:DoubleFJ の Blog

數組拷貝方式

直接先貼出測試代碼:

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[];
        stu[] = new Student(, , "男");
        stu[] = new Student(, , "女");
        stu[] = new Student(, , "嬲");
        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 + );
        arrayCopyStu[stu.length] = new Student(, , "奻");
        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[];
        System.arraycopy(stu, , systemCopyStu, , 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[].setAge();
        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 :
stu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲]]
stu address :[Lcom.tonglei.test.Student;@dea4e
<------------------------------------->
arrayCopyStu length :
arrayCopyStu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲], Student :[ , ,奻]]
arrayCopyStu address :[Lcom.tonglei.test.Student;@c647e05
<------------------------------------->
systemCopyStu length :
systemCopyStu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲], null]
systemCopyStu address :[Lcom.tonglei.test.Student;@
<------------------------------------->
<---------改變了原數組第一個對象的age------->
<------------------------------------->
stu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲]]
arrayCopyStu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲], Student :[ , ,奻]]
systemCopyStu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲], null]
           

Arrays.copyOf

Arrays.copyOf

方法傳回一個新數組,不僅僅隻是拷貝原數組中的元素會建立一個新的數組對象

上述測試結果 :

<------------------------------------->
arrayCopyStu length :
arrayCopyStu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲], Student :[ , ,奻]]
arrayCopyStu address :[Lcom.tonglei.test.Student;@c647e05
<------------------------------------->
           

可以看出,copy原數組中元素并擴容了一長度,同時

arrayCopyStu[stu.length] = new Student(14, 140, "奻");

對新增元素指派,進而列印出的便是上述内容。

System.arraycopy

System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

方法隻拷貝已經存在數組元素,參數依次為原數組、原數組拷貝起始位址、目标數組、目标數組拷貝起始位址、拷貝長度。

上述測試結果 :

<------------------------------------->
systemCopyStu length :
systemCopyStu :[Student :[ , ,男], Student :[ , ,女], Student :[ , ,嬲], null]
systemCopyStu address :[Lcom.tonglei.test.Student;@
<------------------------------------->
           

可見,新數組隻從原數組中拷貝了存在的指定個數元素并可以指定拷貝到目标數組中。

Arrays.copyOf()

的源碼中可知其底層還是調用了

System.arrayCopyOf()

方法。

進而探究

兩種均可對數組進行copy,但是

Arrays.copyOf()

System.arrayCopyOf()

兩種方法所copy生成的新的數組對象中的元素對象到底是新的還是依舊指向原先的呢?來一探究竟!

然而細心的同學已經心領神會..測試代碼早早貼在了上面!

System.out.println("<------------------------------------->");
System.out.println("<---------改變了原數組第一個對象的age------->");
System.out.println("<------------------------------------->");

// 改變原數組的資料
stu[].setAge();
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(, , "男");
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差不多不過報錯資訊更為詳細,純粹這次簡單測試個人體會)

參考博文

  • 關于Java 拷貝數組方法 Arrays.copyOf() 是位址傳遞還是值傳遞
  • Java對象拷貝(BeanUtil.copyProperties 方法)
  • Java開發中beancopy比較
  • Java對象間屬性值的複制-Spring的BeanUtil

具體方法具體場景各自選擇。 END.

繼續閱讀