小工具知识网

当前位置: 首页 > 行业知识 > 【Java SE】接口实例——Cloneable 关于深拷贝与浅拷贝

行业知识

【Java SE】接口实例——Cloneable 关于深拷贝与浅拷贝

2026-10-28 06:51:34 来源:互联网转载

来都来了,不妨点个关注叭!

博客主页:欢迎各位大佬!

本期内容将会进一步了解接口实例Clonable接口,深入理解接口与抽象类的区别,并讲解Object类的方法,我们一起来看看吧!

文章目录

  • 1. Clonable接口
    • 1.1 Clonable接口
    • 1.2 浅拷贝 vs 深拷贝
      • 1.2.1 浅拷贝
      • 1.2.1 如何实现深拷贝
      • 2. 接口与抽象类的区别
      • 3. Object类
        • 3.1 toString()方法
        • 3.2 equals()方法
        • 3.3 hashCode()方法

          1. Clonable接口

          1.1 Clonable接口

          Java 中内置了一些很有用的接口,比如Clonable接口!

          Object 类中存在一个clone方法,调用这个方法可以创建一个对象的"拷贝",但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口,否则就会抛出 CloneNotSupportedException 异常

          我们先来看看以下代码,clone方法的具体使用~

          class Person implements Cloneable {    private String name;    public Person clone() {        Person o = null;        try {            o = (Person) super.clone();        }catch (CloneNotSupportedException e) {            e.printStackTrace();        }        return o;    }}public class Test {    public static void main(String[] args) {        Person p1 = new Person();        Person p2 = p1.clone();        System.out.println(p1 == p2);    }}

          打印结果如下:

          这里打印的为什么是false呢?不是拷贝了一模一样的对象嘛~其实,clone()方法拷贝的是"浅拷贝",什么是"浅拷贝",什么是"深拷贝",请往下继续看!

          1.2 浅拷贝 vs 深拷贝

          1.2.1 浅拷贝

          Cloneable 拷贝出的对象是一份"浅拷贝"

          观察以下代码:

          class Money {    public double m = 99.0;}class Person implements Cloneable {    //Person类包含money对象    public String name;    public Money money = new Money();    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }    Person(String name) {        this.name = name;    }}public class Test {    public static void main(String[] args) throws CloneNotSupportedException {        Person p1 = new Person("球球");        Person p2 = (Person) p1.clone();        System.out.println("通过p2修改前的结果");        System.out.println(p1.name);        System.out.println(p2.name);        System.out.println(p1.money.m);        System.out.println(p2.money.m);        p2.money.m = 12.2;        p2.name = "优优";        System.out.println("通过p2修改后的结果");        System.out.println(p1.name);        System.out.println(p2.name);        System.out.println(p1.money.m);        System.out.println(p2.money.m);    }}

          打印结果如下:

          如上代码与打印结果可知道,通过clone方法,只是拷贝Person对象,对于Person对象中的Money对象,并没有拷贝。通过p2这个引用修改了m的值后,person1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝!!!

          通过下图,我们也能知道为什么上述打印结果为false,因为clone方法拷贝对象,开辟了新的内存空间,并不是指的同一个内存空间地址,所以打印false,==比较的是两个对象的地址!!!

          1.2.1 如何实现深拷贝

          如何实现深拷贝呢~(深拷贝即拷贝对象中的对象,修改拷贝后的对象中对象的值,不改变被拷贝对象中对象的值)

          这里采用重写clone方法实现对象的深拷贝,即在Money实现Cloneable接口,重写clone方法

          实现步骤:

          1)Money类实现Clonable接口,并实现clone方法

          2)修改Person类实现的clone方法,不仅需要实现person对象的克隆,同时克隆Money对象

          具体实现的完整代码如下:

          class Person implements Cloneable {    private String name;    private Money money;    public Money getMoney() {        return money;    }    public void setMoney(Money money) {        this.money = money;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    // 实现克隆Person对象    @Override    protected Person clone() throws CloneNotSupportedException {        money = this.money.clone();        return (Person) super.clone();    }}class Money implements Cloneable {    private double m;    // 实现克隆Money对象    @Override    protected Money clone() throws CloneNotSupportedException {        return (Money) super.clone();    }    public double getMoney() {        return m;    }    public void setMoney(double m) {        this.m = m;    }}public class Test {    public static void main(String[] args) throws CloneNotSupportedException {        Person p1 = new Person();        p1.setName("球球");        Money money = new Money();        money.setMoney(99.0);        p1.setMoney(money);        Person p2 = p1.clone();        System.out.println("通过p2修改前的结果");        System.out.println(p1.getName());        System.out.println(p2.getName());        System.out.println(p1.getMoney().getMoney());        System.out.println(p2.getMoney().getMoney());        System.out.println("通过p2修改后的结果");        p2.setName("优优");        money.setMoney(12.2);        p2.setMoney(money);        System.out.println(p1.getName());        System.out.println(p2.getName());        System.out.println(p1.getMoney().getMoney());        System.out.println(p2.getMoney().getMoney());    }}

          打印结果如下:

          2. 接口与抽象类的区别

          抽象类和接口都是 Java 中多态的常见使用方式,都需要我们重点掌握,同时又要认清两者的区别

          (重要!!! 常见面试题)

          【核心区别】

          抽象类中可以包含普通方法和普通字段,这样的普通方法和字段可以被子类直接使用(不必重写)

          接口中不能包含普通方法,子类必须重写所有的抽象方法

          abstract class Person {    public String name;    Person(String name) {        this.name = name;    }}

          Person中包含一个 name 这样的属性,这个属性在任何子类中都是存在的,因此Person类只能作为一个抽象类,而不应该成为一个接口(当然Person类也可以是普通类,这里只是举一个例子~)

          【注意】

          抽象类存在的意义是为了让编译器更好的校验,像Person这样的类我们并不会直接使用,而是使用它的子类,故把Person类设置为抽象类更合理,比如一不小心创建Person类的实例,编译器会校验,会及时提醒我们这里有问题~

          详细区别如下图所示:

          3. Object类

          之前我们经常提到Object类,这到底是一个什么样的类呢?我们一起来看看吧~

          【Object类】

          Object是Java默认提供的一个类,Java里面除了Object类,所有的类都是存在继承关系默认会继承Object父类,即所有类的对象都可以使用Object的引用进行接收!!!

          【使用案例】使用Object类接收所有类的对象

          class Person{}class Student{}public class Test {    public static void main(String[] args) {        function(new Person());        function(new Student());    }    public static void function(Object obj) {        System.out.println(obj);    }}

          打印结果如下:

          这里有一个缺点,可以看到,每次要一个对象都需要new一个

          适用场景:对象只用一次的时候

          在开发之中,Object类是参数的最高统一类型,Object类也存在很多定义好的一些方法(在Java API帮助手册上看)如下:

          接下来主要熟悉这三个个方法:toString()方法,equals()方法,hashCode()方法(前两个方法在之前期的内容中具体介绍过,这里不作过多介绍~)hashCode方法将在数据结构专栏中介绍,敬请期待!

          3.1 toString()方法

          返回对象的字符串表示

          public String toString() {    return getClass().getName() + "@" + Integer.toHexString(hashCode());}

          【注意】根据自己想要返回的值,可以进行重写

          3.2 equals()方法

          某个对象是否"等于"该对象

           public boolean equals(Object obj) {        return (this == obj);   }

          Object中equals的实现直接比较的是两个引用变量的地址,有些情况下,需要比较的是对象中的内容,这时需要重写equals方法

          3.3 hashCode()方法

          返回对象的哈希码值

          本期内容回顾

          ✨✨✨本期内容到此结束啦~下期再见!

上一篇:csgo怎么选香港服务器吗?

下一篇:服务器代理怎么改?