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。

java cloneable 接口_Cloneable 接口 记号接口(标记接口)相关推荐

  1. 什么是Java Marker Interface(标记接口)

    先看看什么是标记接口?标记接口有时也叫标签接口(Tag interface),即接口不包含任何方法.在Java里很容易找到标记接口的例子,比如JDK里的Serializable接口就是一个标记接口. ...

  2. 什么是Java Marker Interface(标记接口) 1

    先看看什么是标记接口?标记接口有时也叫标签接口(Tag interface),即接口不包含任何方法.在Java里很容易找到标记接口的例子,比如JDK里的Serializable接口就是一个标记接口. ...

  3. java的标记接口_Java中的标记接口?

    我被教授,Java中的Marker接口是一个空接口,用于向编译器或JVM发送信号,实现此接口的类的对象必须以特殊方式处理,如序列化,克隆等. 但最近我了解到,它实际上与编译器或JVM无关.例如,在Se ...

  4. java中的标记接口

    在java 中,RandomAccess和Cloneable .Serializable一样,都是标志性接口,不需要任何实现,只是又来表明其实现类具体有某种特质的,实现了Cloneable表明可以拷贝 ...

  5. java 标记_java – 标记注释与标记接口

    在阅读有关Marker接口的文章时,我偶然发现了以下网站:Item 37: Use marker interfaces to define types 根据Joshua Bloch的说法,Marker ...

  6. 标记接口,注解和注解处理器的前世今生

    文章目录 简介 注解的起源和marker interfaces 注解的定义 Retention Target 自定义参数 在运行时使用注解 在编译时使用注解 总结 简介 相信大部分的开发者都用过注解, ...

  7. 根据XML配置规则导入Excel数据(⑥)ExcelAble 标记接口

    就是一个支持Excel标记接口,还提供验证功能. package com.ivfly.xlsbean; import java.io.Serializable;  public interface E ...

  8. Java的类(class)、包(package)和接口(interface)

    在Java中,类(class)是用来代表对象的基本单元.对象(object)可以是现实世界中的任何一个实体,它具有若干区别于其它对象的属性和操作.而类则通过为对象定义属性和操作来概括一类实体.它封装了 ...

  9. Java中常用的类,包,接口

    Java中常用的类,包,接口 包名 说明 java.lang 该包提供了Java编程的基础类,例如 Object.Math.String.StringBuffer.System.Thread等,不使用 ...

最新文章

  1. 华为鲲鹏产业生态加速算力升级,企业数字化转型在山西吹响号角
  2. 存储过程结果更改编码_Docker安装Minio存储服务器详解
  3. 皮一皮:论家庭地位...
  4. EBCDIK,EBCDIC,ASCII,shift JIS間の変換
  5. 37 Reasons why your Neural Network is not working
  6. 用hundred造句子_关于冬至的问候短句,冬至文案唯美句子
  7. excel中线性函数_Excel中特别有用的不常用函数之Indirect函数
  8. linux5 syscall 流程_Linux的上的程序是如何运行的,api机制是怎么样?
  9. oracle test传入参数,oracle存储过程,test(测试)时传自定义类型参数问题
  10. linux虚拟机能通显卡吗,英伟达 GeForce 游戏显卡正式支持虚拟机传递功能,可以完全调用...
  11. 数据库操作导入导出以及加快查询速度
  12. Android 应用程序模块: 应用, 任务, 进程, 和线程
  13. three.js 学习1
  14. 常用传感器讲解九--雨滴传感器
  15. 制作粉色少女系列 生日快乐祝福网页(HTML+CSS+JS)
  16. vue读取Excel并分组处理数据显示
  17. 360公司 2020秋招 技术综合E卷 在线考试 编程题 第一题 表面积(web前端)
  18. windows PE 是什么?
  19. 如何给apk文件签名(一)
  20. 2021华为软件精英挑战赛(杭厦第20名)

热门文章

  1. 激光雷达人眼安全认证
  2. Java MP3转base64
  3. CSDN编程竞赛 ——— 第六期
  4. OSPF邻居状态机停留原因解析
  5. 2017第48周四乔布斯语录
  6. 常见MIDI信息的状态位和数据位含义表
  7. 最近被吞噬星空动漫吸引,那就愉快的爬取一下小说看看吧!----Python爬虫
  8. react 响应式图片放大镜 (伸缩盒子)
  9. haha, 愚人节听鱼人歌
  10. r语言nonzerocoef函数_R语言第六章机器学习①R中的逐步回归要点