大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺
Cloneable 接口指示了一个类提供了一个安全的clone方法。
首先了解Object.clone()方法:
clone是Object超类的一个protected方法,用户代码不能直接调用这个方法。Object的子类只能调用Object超类中受保护的clone方法来克隆它自己的对象,必须重新定义clone为public才能允许所有方法调用这个类的实例的clone方法克隆对象。
clone方法的作用:clone方法对Employee调用它对这个对象一无所知,所以只能逐个域地进行拷贝。a. 如果对象中的所有数据域都是数值或者其他基本类型,拷贝这些域没有问题;b. 但是如果对象中包含子对象的引用,拷贝域就会得到相同子对象的另一个引用(浅拷贝)。这样一来,原对象和克隆的对象仍然会共享一些信息。
浅拷贝的影响:如果原对象和浅克隆对象共享的子对象是不可变的,那么这种共享就是安全的。如果子对象属于一个不可变的类,如String,就是这种情况。或者在对象的生命周期中,子对象一直包含不变的常量,没有更改器会改变它,就是没有方法会生成它的引用,这种情况同样是安全的(举个栗子:下面例子中hiereDay是一个Date对象,Date类的域是可变的,所以hireDay需要深拷贝。而LocalDate的域不可变,如果hireDay是不可变的LocaDate类的一个实例,就无需我们做任何处理了)。
public class Employee implements Cloneable {
private String name;
private double salary;
private Date hireDay;
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
hireDay = new Date();
}
@Override
public Employee clone() throws CloneNotSupportedException
{
// call Object.clone() Employee cloned = (Employee) super.clone(); // clone会逐个域的进行拷贝
// clone mutable fields cloned.hireDay = (Date) hireDay.clone();
return cloned;
}
public void setHireDay(int year, int month, int day)
{
Date newHireDay = new GregorianCalendar(year, month – 1, day).getTime();
// Example of instance field mutation hireDay.setTime(newHireDay.getTime());
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString()
{
return “Employee[name=” + name + “,salary=” + salary + “,hireDay=” + hireDay + “]”;
}
}
public class Main {
public static void main(String[] args)
{
Employee employee = new Employee(“jack1”, 20000);
try {
Employee clone = employee.clone();
employee.raiseSalary(20);
employee.setHireDay(2020, 10, 22);
System.out.println(employee.toString());
System.out.println(clone.toString());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
/*** 输出:Employee[name=jack1,salary=24000.0,hireDay=Thu Oct 22 00:00:00 CST 2020]Employee[name=jack1,salary=20000.0,hireDay=Sun Oct 13 17:47:26 CST 2019]*/
再看一个栗子,hireDay为不可变LocalDate类的实例时(private LocalDate hireDay;),Main.java类代码基本不变(构造函数有改变 -> Employee employee =newEmployee(“jack1”,20000,2019,10,13);):
public class Employee implements Cloneable {
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year, int month, int day)
{
this.name = name;
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
}
@Override
public Employee clone() throws CloneNotSupportedException
{
// call Object.clone() Employee cloned = (Employee) super.clone();
// // clone mutable fields// cloned.hireDay = (Date) hireDay.clone();
return cloned;
}
public void setHireDay(int year, int month, int day)
{
// Date newHireDay = new GregorianCalendar(year, month – 1, day).getTime();// // Example of instance field mutation// hireDay.setTime(newHireDay.getTime()); hireDay = LocalDate.of(year, month, day);
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
public String toString()
{
return “Employee[name=” + name + “,salary=” + salary + “,hireDay=” + hireDay + “]”;
}
}
对于一个要实现clone方法的类,需要确定:实现Cloneable接口;
重新定义clone方法,并且制定public访问修饰符。
注意:
Cloneable接口的出现与接口的正常实现没有关系。具体讲,它(Cloneable接口)没有指定clone方法,这个方法是从Object类继承的(应该是实现接口的类从Object类继承)。Cloneable接口的作用只是作为一个标记,指示 类设计者 了解克隆过程。对象对于克隆很“偏执”,如果一个对象请求克隆,但没有实现这个接口,就会生成一个受查异常(报错:java.lang.CloneNotSupportedException)。
Cloneable接口是Java提供的一组标记接口(tagging interface)之一。有些程序员也称之为记号接口(marker interface)。注意:Comparable等接口的通常用途是确保一个类实现一个或一组特定的方法。标记接口不包含任何方法,它唯一的作用就是允许在类型查询中使用instanceof:
if (obj instanceof Cloneable) ..
建议自己程序中不要使用标记接口。
即使clone的默认(浅拷贝)实现能够满足要求,还是需要实现Cloneable接口,将clone方法重新定义为public,再调用super.clone()。
class Employee implements Cloneable()
{
// raise visibility level to public, change return type public Employee clone() throws CloneNotSupportedException
{
return (Employee) super.clone();
}
…
}
如果一个类重写了clone方法,但是类没有声明实现接口 implements Cloneable,类会抛出一个CloneNotSupportedException异常。当然,Employee和Date类实现了Cloneable接口,所以不会抛出这个异常。不过编译器不会了解这一点,所以我们声明了这个异常:
public Employee clone() throws CloneNotSupportedException
这样,子类在不支持克隆时选择抛出一个CloneNotSupportedException异常。
clone没有想象中的那么常用,标准库中只有5%的类实现了clone。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/184369.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...