开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情
前言
在java当中,我们经常会看到这样的代码:
Object obj = xxx.clone();
这个代码的作用就是拷贝一个xxx的实例;在开发过程中,拷贝实例是很常见的操作,如果一个类中的字段特别多,我们还通过一个一个字段来实现拷贝的话,那么整个代码就会特别地冗长;为了避免这个问题,我们就可以通过实现Cloneable接口来让实例拥有拷贝的能力;
代码示例
接下来我们来看一下如何实现自定义的实例克隆:
@ToString
static class Person implements Cloneable {
private String name;
private int age;
Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
上述代码中,我们的Person实现了Cloneable接口,并且重写了Object类的clone()方法,这样的话我们的Person就具备克隆的功能了;
注意:@ToString重写了toString()方法,为了能够直接打印出Person实例,而不是它的地址;
下面我们编写main方法来测试一下是否满足我们的要求:
public static void main(String[] args) throws CloneNotSupportedException {
// 创建一个Person实例
Person person = new Person("zouwei", 20);
// 执行clone()
Person clonePerson = (Person) person.clone();
// 分别打印Person实例和克隆的实例
System.out.println("person:" + person);
System.out.println("clonePerson:" + clonePerson);
// 检查Person实例和克隆实例是否是同一个对象
System.out.println("person==clonePerson:" + (person == clonePerson));
}
最终输出结果如下:
person:Person(name=zouwei, age=20)
clonePerson:Person(name=zouwei, age=20)
person==clonePerson:false
通过上述示例可以判断,我们的拷贝功能是实现成功的;
为何要实现Cloneable
我们看一下Cloneable源码,发现里面啥方法都没有:
public interface Cloneable {
}
我们可不可以不实现这个接口,然后直接重写clone()方法?最终我们发现如果没有实现这个Cloneable接口的话,在调用clone()方法时会出现以下异常:
Exception in thread "main" java.lang.CloneNotSupportedException: com.example.awesomerocketmq.controller.Person
at java.base/java.lang.Object.clone(Native Method)
at com.example.awesomerocketmq.controller.Person.clone(TestController.java:80)
at com.example.awesomerocketmq.controller.TestController.main(TestController.java:87)
这个异常是Object.clone()方法抛出来的,它是一个Native Method,也就是说这个方法的具体实现是底层JVM实现的;
我们在Object.clone()方法的注释里面可以看到这么一段话:
Throws:
CloneNotSupportedException – if the object's class does not support the Cloneable interface. Subclasses that override the clone method can also throw this exception to indicate that an instance cannot be cloned.
大概的意思就是,如果抛出CloneNotSupportedException异常,那是因为对应的类没有实现Cloneable接口;重写 clone 方法的子类也可以抛出这个异常来表示一个实例不能被克隆;
很显然,我们的Person并没有在重写clone()方法时抛这个CloneNotSupportedException异常,所以原因就在于我们没有实现Cloneable接口;
我们完全可以断定,虽然Cloneable接口里面没有任何可实现的方法,但是它却起到了标识的作用,没有实现Cloneable接口的实例都是无法完成拷贝功能的;