行业知识
【Java SE】接口实例——Cloneable 关于深拷贝与浅拷贝
来都来了,不妨点个关注叭!
博客主页:欢迎各位大佬!
本期内容将会进一步了解接口实例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怎么选香港服务器吗?
下一篇:服务器代理怎么改?