1. 程式人生 > >java物件的淺拷貝和深拷貝

java物件的淺拷貝和深拷貝

淺拷貝

java的資料型別有基本資料型別(如:int、long等)和引用資料型別。例如:物件1中有屬性a(基本資料型別)和屬性b(引用資料型別),在進行淺拷貝到物件2時,屬性a複製屬性的值給物件2,這樣物件1和物件2修改屬性a時不會相互影響。屬性b則是複製一份引用(即記憶體地址)給物件2,這樣物件1修改屬性b後,物件2中的值也會改變。

一般通過Object的clone( )方法來實現淺複製,使用clone( )方法需要實現Cloneable介面。

clone( )方法的基本規則如下:

1、基本資料型別

進行值的拷貝,例如:int、long、byte等。

2、String

如果變數是String型別,則拷貝其地址引用,但是因為java中String是不變的,所以在修改的時候是新建一個String,這樣新物件指向新地址不影響舊物件的值。

3、物件

物件的拷貝是複製其引用地址,即新物件和原來物件共用一個物件例項。

package com.hs.copy;

public class Age {

    private int age;
    
    

    public Age(int age) {
        super();
        this.age = age;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Age [age=" + age + "]";
    }

    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
    
}

 

package com.hs.copy;

public class Person implements Cloneable{

    private String name;
    
    private Age age;
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = new Age(age);
    }

    public Person clone(){
        
        try {
            
            return (Person)super.clone();
            
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age.getAge() + "]";
    }



    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the age
     */
    public Age getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(Age age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

/**
 * 淺拷貝
 * @author Administrator
 *
 */
public class ShallowCopy {

    public static void main(String[] args) {
        
        Person person1 = new Person("yang", 18);
        System.out.println( "person1 : " + person1.toString() );
        
        Person person2 = person1.clone();
        System.out.println( "person2 : " + person2.toString() );
        
        person2.setName("yyyy");
        System.out.println();
        System.out.println( "-----修改基本型別變數後-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
        person2.getAge().setAge(20);
        System.out.println();
        System.out.println( "-----修改引用型別變數後-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
    }

}

執行結果:

person1 : Person [name=yang, age=18]
person2 : Person [name=yang, age=18]

-----修改基本型別變數後-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=18]

-----修改引用型別變數後-----
person1 : Person [name=yang, age=20]
person2 : Person [name=yyyy, age=20]

 

深拷貝

通過上面的學習,很容易發現淺拷貝有個缺陷,即變數是引用型別時並沒有實現值的拷貝。這時候就要用到深拷貝來實現了。如下是深拷貝的兩種實現。

一、將引用型別的變數以及變數的變數全部實現clone( )方法

該實現的缺點:當引用型別的變數很多、很深時,程式碼量很大

package com.hs.copy;

public class Age implements Cloneable{

    private int age;
    
    

    public Age(int age) {
        super();
        this.age = age;
    }
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Age [age=" + age + "]";
    }

    /**
     * 深拷貝-新增
     */
    public Age clone(){
        
        try {
            return (Age)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }

    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

public class Person implements Cloneable{

    private String name;
    
    private Age age;
    
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = new Age(age);
    }

    /**
     * 深拷貝
     */
    public Person clone(){
        
        try {
            
            Person person = (Person)super.clone();
            Age age = person.age.clone();
            person.setAge(age);
            return person;
            
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }
    
    
    /**
     * 淺拷貝
     */
    /*public Person clone(){
        
        try {
            
            return (Person)super.clone();
            
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
        
    }*/
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age.getAge() + "]";
    }



    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the age
     */
    public Age getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(Age age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

/**
 * 深拷貝
 * @author Administrator
 *
 */
public class DeepCopy {

    public static void main(String[] args) {
        
        Person person1 = new Person("yang", 18);
        System.out.println( "person1 : " + person1.toString() );
        
        Person person2 = person1.clone();
        System.out.println( "person2 : " + person2.toString() );
        
        person2.setName("yyyy");
        System.out.println();
        System.out.println( "-----修改基本型別變數後-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
        person2.getAge().setAge(20);
        System.out.println();
        System.out.println( "-----修改引用型別變數後-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
    }

}

結果:

person1 : Person [name=yang, age=18]
person2 : Person [name=yang, age=18]

-----修改基本型別變數後-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=18]

-----修改引用型別變數後-----
person1 : Person [name=yang, age=18]
person2 : Person [name=yyyy, age=20]

 

二、通過物件的序列化,再反序列化實現深拷貝

package com.hs.copy;

import java.io.Serializable;

public class AgeDeep implements Serializable{

    private int age;
    
    

    public AgeDeep(int age) {
        super();
        this.age = age;
    }
    
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Age [age=" + age + "]";
    }


    /**
     * @return the age
     */
    public int getAge() {
        return age;
    }

    /**
     * @param age the age to set
     */
    public void setAge(int age) {
        this.age = age;
    }
    
    
    
}

 

package com.hs.copy;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class PersonDeep implements Serializable {

    private String name;
    
    private AgeDeep age;
    
    public PersonDeep(String name, int age) {
        super();
        this.name = name;
        this.age = new AgeDeep(age);
    }

    public PersonDeep deepClone(){
        
        ObjectOutputStream objectOutputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            //序列化
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);
            
            //反序列化
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (PersonDeep)objectInputStream.readObject();
            
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                if( objectOutputStream != null ){
                    objectOutputStream.close();
                }
                if( objectInputStream != null ){
                    objectInputStream.close();
                }
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
        
    }
    

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age.getAge() + "]";
    }



    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }




    /**
     * @return the age
     */
    public AgeDeep getAge() {
        return age;
    }




    /**
     * @param age the age to set
     */
    public void setAge(AgeDeep age) {
        this.age = age;
    }

    
    
    
}

 

package com.hs.copy;

/**
 * 深拷貝
 * @author Administrator
 *
 */
public class DeepCopy {

    
    
    /**
     * 序列化深拷貝
     * @param args
     */
    public static void main(String[] args) {
        
        PersonDeep person1 = new PersonDeep("yang", 18);
        System.out.println( "person1 : " + person1.toString() );
        
        PersonDeep person2 = person1.deepClone();
        System.out.println( "person2 : " + person2.toString() );
        
        person2.setName("yyyy");
        System.out.println();
        System.out.println( "-----修改基本型別變數後-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
        
        person2.getAge().setAge(20);
        System.out.println();
        System.out.println( "-----修改引用型別變數後-----");
        System.out.println( "person1 : " + person1.toString() );
        System.out.println( "person2 : " + person2.toString() );
    }

}