Java笔记:数组的四种拷贝方式

0 复制的方式

将一个对象的引用复制给另外一个对象,一共有三种方式:

  • 直接赋值
  • 浅拷贝
  • 深拷贝

首先看看深拷贝和浅拷贝的概念,在 Java 中,除了基本数据类型之外,还有引用数据类型。而一般使用 "=" 做赋值操作的时候,对于基本数据类型,实际上是拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,他们实际上还是指向的同一个对象。而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝

1)浅拷贝:(复制引用但不复制引用的对象)

对基本数据类型进行值传递,对引用数据类型进行了引用传递

浅拷贝
2)深拷贝:(复制对象和其应用对象)
对基本数据类型进行值传递,对引用数据类型,则创建了一个新的对象,并复制了其内容
深拷贝

1 for循环(数值拷贝)
public static void main(String[] args) {
    int[] array = new int[]{1,2,3,4,5};
    int[] arraycopy = new int[5];
    for(int i=0;i<array.length;i++){
        arraycopy[i]=array[i];
    }
    arraycopy[0]=90;
    for(int x:array){
        System.out.print(x+" "); //1 2 3 4 5 
    }
    System.out.println();
    for(int x:arraycopy){
        System.out.print(x+" ");//90 2 3 4 5 
    }
}
2 System.arraycopy()
class Student{
     private int age=10;

     public Student(int age) {
         this.age = age;
     }

     public int getAge() {
         return age;
     }

     public void setAge(int age) {
         this.age = age;
     }
 }
public class Main {
    public static void main(String[] args) {
        Student[] students=new Student[2];
        students[0]=new Student(15);
        students[1]=new Student(25);
        Student[] teachers = new Student[2];
        System.arraycopy(students,0,teachers,0,students.length);
        for(Student x:students){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        for(Student x:teachers){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        System.out.println("************");
        students[0].setAge(99);
        for(Student x:students){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        for(Student x:teachers){
            System.out.print(x.getAge()+" ");
        }
    }
 }

浅拷贝:
15 25
15 25


99 25
99 25

//System.arraycopy()方法java源代码中的代码
public static native void arraycopy(Object src,  int  srcPos,
                               Object dest, int destPos,
                              int length);

native方法为本地方法,效率较高。
src :源地址
srcPos:源地址开始位置
dest:目的地
destPos:目的地的开始位置
length:拷贝的长度

3 Arrays.copyOf()方法

Arrays.copyOf(源数组,指定数组长度),底层调用的是System.arraycopy(), Arrays.copyOf()方法会产生一个新的对象,但依然是浅拷贝

class Student{
     private int age=10;

     public Student(int age) {
         this.age = age;
     }

     public int getAge() {
         return age;
     }

     public void setAge(int age) {
         this.age = age;
     }
 }
public class Main {
    public static void main(String[] args) {
        Student[] students=new Student[2];
        students[0]=new Student(15);
        students[1]=new Student(25);
        Student[] teachers = 
        Arrays.copyOf(students,students.length);
        
        for(Student x:students){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        for(Student x:teachers){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        System.out.println("************");
        students[0].setAge(99);
        for(Student x:students){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        for(Student x:teachers){
            System.out.print(x.getAge()+" ");
        }
    }
}

15 25
15 25


99 25
99 25

参考:
https://www.cnblogs.com/xingzc/p/9646923.html

4 Clone, Serializable实现深拷贝
(1)数组元素为数值
public static void main(String[] args) {
    int[] array = new int[]{1,2,3,4,5};
    int[] arraycopy = new int[5];
    arraycopy=array.clone();
    System.out.println(Arrays.toString(array));
    System.out.println(Arrays.toString(arraycopy));
    System.out.println("*****************");
    array[0]=100;
    System.out.println(Arrays.toString(array));
    System.out.println(Arrays.toString(arraycopy));
}

[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]


[100, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

(2)数组元素为引用类型
 class Student{
     private int age=10;

     public Student(int age) {
         this.age = age;
     }

     public int getAge() {
         return age;
     }

     public void setAge(int age) {
         this.age = age;
     }
 }
public class Main {
    public static void main(String[] args) {
        Student[] students=new Student[2];
        students[0]=new Student(15);
        students[1]=new Student(25);
        Student[] teachers = students.clone();
        for(Student x:students){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        for(Student x:teachers){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        System.out.println("************");
        students[0].setAge(99);
        for(Student x:students){
            System.out.print(x.getAge()+" ");
        }
        System.out.println();
        for(Student x:teachers){
            System.out.print(x.getAge()+" ");
        }
    }
 }

15 25
15 25


99 25
99 25

数组之间的引用类型元素实现的也是浅拷贝, 当调用 students[0].setAge(99);后,两个对象的内容都改变了。

(3)对象之间的拷贝

java.lang.Object类的clone()方法为protected类型,不可直接调用,被克隆的类要实现Cloneable接口;然后在该类中覆盖clone()方法,并且在该clone()方法中调用super.clone()。

class Money {
    public double money = 12.5;
}
class Person implements Cloneable{
    public String name;
    public Money m;
    public Person() {
        this.m = new Money();
    }
    // 重写clone方法:Object
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();

        Person person2 = (Person)person.clone();

        System.out.println(person.m.money);
        System.out.println(person2.m.money);

        System.out.println("===================");
        person2.m.money = 99.9;
        System.out.println(person.m.money);
        System.out.println(person2.m.money);
    }

结果显示此时的clone为浅拷贝
12.5
12.5

99.9
99.9

为了实现深拷贝,可以继续使用clone方法,将其内的引用类型变量m进行clone

class Money implements Cloneable{
    double money = 12.5;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
class Person implements Cloneable{
    public String name;
    public Money m;
    public Person() {
        this.m = new Money();
    }
    //重写clone方法:Object
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //return super.clone();
        Person per = (Person) super.clone();
        per.m = (Money)this.m.clone();
        return per;
    }
}

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person();

        Person person2 = (Person)person.clone();

        System.out.println(person.m.money);
        System.out.println(person2.m.money);

        System.out.println("===================");
        person2.m.money = 99.9;
        System.out.println(person.m.money);
        System.out.println(person2.m.money);
    }
}

结果显示为深拷贝

12.5
12.5

12.5
99.9

对象之间进行拷贝时,除了本类需要重写clone方法,其成员变量中若含引用类型,那么该成员变量对应的类也要重写clone方法。

对象克隆有两种方式:

  • 实现Cloneable接口并重写Object类中的clone()方法;
  • 实现Serializable接口,在Java 语言里深复制一个对象,常常可以先让对象实现Serializable 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建对象。通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。

注意:
基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是可以通过泛型类型进行限定,可以判断出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值