JAVA深拷贝和浅拷贝的实现

Java深拷贝和浅拷贝的理解

Java中的对象拷贝主要分为:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。
Java中的数据类型分为基本数据类型引用数据类型。对于这两种数据类型,在进行赋值操作、用作方法参数或返回值时,会有值传递和引用(地址)传递的差别。

浅拷贝

1.通过构造方法实现浅拷贝

package copy;

/**
 * @author zhouxuan
 * @since 2019/5/22
 */
public class ShallowCopy {

    public static void main(String[] agrs){
        Stock stock = new Stock(100);
        Car p1 = new Car("Audi",stock);
        Car p2 = new Car(p1);
        System.out.println("修改前:");
        System.out.println("p1:" + p1.toString());
        System.out.println("p2:" + p2.toString());
        //修改基本数据类型数据
        p1.setBrand("Porches");
        //修改引用类型数据
        stock.setStock(999);
        System.out.println("修改后:");
        System.out.println("p1:" + p1.toString());
        System.out.println("p2:" + p2.toString());
    }

}

class Car {
    private String brand;
    private Stock stock;

    public Car(String brand, Stock stock) {
        this.brand = brand;
        this.stock = stock;
    }
    public Car(Car car){
        this.brand = car.brand;
        this.stock = car.stock;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public Stock getStock() {
        return stock;
    }

    public void setStock(Stock stock) {
        this.stock = stock;
    }

    @Override
    public String toString() {
        return "brand='" + brand + '\'' +
                ", stock=" + stock;
    }
}

class Stock{
    private int stock;

    public Stock(int stock) {
        this.stock = stock;
    }

    public int getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }

    @Override
    public String toString() {
        return ""+this.getStock();
    }
}

运行结果如下:

修改前:
p1:brand='Audi', stock=100
p2:brand='Audi', stock=100
修改后:
p1:brand='Porches', stock=999
p2:brand='Audi', stock=999

从运行结果我们可以看出:
对于基本数据类型(字符串类型)的修改,p1的修改并不会影响p2。
对于引用类型的修改,p2的修改导致了p1中的数据也随之变化。

2.通过重写clone()接口实现浅拷贝
所有类的都有一个Obeject根类,Obeject中提供了clone()方法:
protected native Object clone() throws CloneNotSupportedException;
但我们不能直接调用clone()方法,需要实现Cloneable接口,否则会抛出CloneNotSupportedException异常。我们可以在类中重写clone()方法,实现浅拷贝

public class ShallowCopyClone {
    public static void main(String[] agrs) {
        Price price = new Price(100);
        Computer p1 = new Computer(price, 999);
        Computer p2 = (Computer) p1.copy();
        System.out.println("修改前");
        System.out.println(p1.toString());
        System.out.println(p2.toString());
        p1.setStock(20);
        price.setPrice(123);
        System.out.println("修改后");
        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}

class Computer implements Cloneable{
    private Price price;
    private int stock;

    public Computer(Price price, int stock) {
        this.price = price;
        this.stock = stock;
    }

    public Computer(Computer computer) {
        this.price = computer.price;
        this.stock = computer.stock;
    }

    public Price getPrice() {
        return price;
    }

    public void setPrice(Price price) {
        this.price = price;
    }

    public int getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }

    @Override
    public String toString() {
        return "price=" + price.getPrice() +
                ", stock='" + stock ;
    }

    public Object copy() {
        Object obj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return obj;
    }
}

class Price{
    private int price;

    public Price(int price) {
        this.price = price;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

运行结果:

修改前:
price=100, stock='999
price=100, stock='999
修改后:
price=123, stock='20
price=123, stock='999

深拷贝

深拷贝将对所有对象开辟新的内存空间而不是引用。
如A对象包含B对象,则会对A、B对象开辟新的内存空间实现拷贝。此时修改拷贝前后对象不会互相造成影响。
1.通过序列化和反序列化实现深拷贝
需要拷贝的类实现Serializable接口,否则会抛出NotSerializableException异常。

public class DeepCopy {
    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Category category = new Category(1);
        Watch p1 = new Watch("high", category);

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        //将p1序列化
        oos.writeObject(p1);
        oos.flush();
        //反序列化
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        Watch p2 = (Watch) ois.readObject();
        System.out.println("修改前:");
        System.out.println(p1.toString());
        System.out.println(p2.toString());
        System.out.println("修改后:");
        p1.setLevel("low");
        category.setCategory(2);
        System.out.println(p1.toString());
        System.out.println(p2.toString());
    }
}

class Watch implements Serializable{
    private String level;
    private Category category;

    public Watch(Watch watch) {
        this.level = watch.level;
        this.category = watch.category;
    }

    public Watch(String level, Category category) {
        this.level = level;
        this.category = category;
    }

    public String getLevel() {
        return level;
    }

    public void setLevel(String level) {
        this.level = level;
    }

    public Category getCategory() {
        return category;
    }

    public void setCategory(Category category) {
        this.category = category;
    }

    @Override
    public String toString() {
        return "Watch{" +
                "level='" + level + '\'' +
                ", category=" + category +
                '}';
    }
}

class Category implements Serializable{
    private int category;

    public Category(int category) {
        this.category = category;
    }

    public int getCategory() {
        return category;
    }

    public void setCategory(int category) {
        this.category = category;
    }

    @Override
    public String toString() {
        return "Category{" +
                "category=" + category +
                '}';
    }
}

运行结果:

修改前:
Watch{level='high', category=Category{category=1}}
Watch{level='high', category=Category{category=1}}
修改后:
Watch{level='low', category=Category{category=2}}
Watch{level='high', category=Category{category=1}}

你可能感兴趣的:(java开发)