博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中的clone(+标记接口说明)
阅读量:4145 次
发布时间:2019-05-25

本文共 4662 字,大约阅读时间需要 15 分钟。

复习一下clone,顺便整理下笔记
clone即复制
你有一个引用为A的对象,我也想要一个一模一样的对象,如果能复制出来一个就好啦
在java里面提供了这种复制的操作--clone
为了笔记的完整性,先给出一个更基础的
错误例子
下面是一个普通的Animal类
public class Animal implements Cloneable{    public String name = "";    public boolean lovely = true;    protected ArrayList
foodList = new ArrayList
(); protected Personal personal; static class Personal implements Cloneable{ public int age = 0; public Personal clone() throws CloneNotSupportedException{ return (Personal) super.clone(); } } public Animal clone() throws CloneNotSupportedException{ return (Animal) super.clone(); } public List
getFoodList(){ return foodList; } public void addFood(String f){ foodList.add(f); }}
这里有一个Personal的内部静态类,一会再看这个东西,先忽略
如果真的有人想复制对象,但是又写成了下面的代码,那么他真应该好好看看基础了
public static void main(String[] args) {    Animal animal = new Animal();    animal.lovely = false;        Animal animalCopy = animal;    animalCopy.lovely = true;    System.out.println(animal.lovely);    System.out.println(animalCopy.lovely);}
这里Animal animalCopy = animal;只是新建了一个Animal的引用而已
对象呢,还是原先的对象,
两个引用指向同一个对象
如果对象改变了,那么animal.lovely和animalCopy.lovely的值也都会改变。因为他们本来就是同一个对象的lovely,当然一起变了,所以结果都是true
如果想clone,我们可以通过clone来实现
clone是
Object的方法,发现这个方法是
protected的,返回类型是Object
如果外面想调用它,那起码要先变成public的,这样还不行,Personal还要实现Cloneable才可以
那我们看看Cloneable里面都是些神马吧
public interface Cloneable {}
- -
里面神马也没有,那它有啥作用?
obj instanceof Cloneable
恩,可以这么写,似乎只能作为
类型检查来用了
既然要去Animal必须实现Cloneable这个接口,那么看来clone时候是需要做类型检查的
这种接口在结尾再继续说明
try {    Animal animalCopy = (Animal)animal.clone();    animalCopy.lovely = true;    System.out.println(animal.lovely);    System.out.println(animalCopy.lovely);} catch (CloneNotSupportedException e) {    e.printStackTrace();}
这回打印的结果是false和true了
clone貌似很简单,可是很不幸,这只是简单的情形而已
这时候看看Personal这个类吧
Personal p = new Personal();p.age = 1;animal.personal = p;
给animal对象一个personal属性,我们看看结果会怎样
try {    Animal animalCopy = (Animal)animal.clone();    animalCopy.lovely = true;    System.out.println(animal.lovely);    System.out.println(animal.personal.age);    System.out.println(animalCopy.lovely);    System.out.println(animalCopy.personal.age);    animalCopy.personal.age = 2;    System.out.println(animal.lovely);    System.out.println(animal.personal.age);    System.out.println(animalCopy.lovely);    System.out.println(animalCopy.personal.age);} catch (CloneNotSupportedException e) {    e.printStackTrace();}/false1true1false2true2
lovely和预想的一样,一个true一个false,但是age似乎就有些问题了
我们明明只改动了lovely动物的age,为啥不lovely的动物也跟着涨了一岁!
clone分为深clone和浅clone
浅clone只clone对象中的基本类型
深clone随意clone了,想clone就clone什么,可惜java并没为大家实现深clone
上面的例子personal没有被clone
那么我们在animal的clone来实现

public Animal clone() throws CloneNotSupportedException{    Animal a = (Animal) super.clone();    a.foodList =  (ArrayList
)foodList.clone(); if(personal != null){ a.personal = personal.clone(); } return a;}
看出我们的Personal类也需要实现Cloneable接口,重写clone方法

这时候我们再运行之前的代码,结果正确
不lovely的动物age=1,lovely的动物age=2
我们还会发现animal的foodList也被clone了(代码省略)
之所以可以这么写foodList.clone();,是因为sun帮我们实现了clone

目前我们有了lovely和不lovely的动物,还没有给他们起名字呢,一个叫lion一个叫dog好了

public static void main(String[] args) {    Animal animal = new Animal();    animal.name="lion";    try {        Animal animalCopy = (Animal)animal.clone();        animalCopy.name = "dog";        System.out.println(animal.name);        System.out.println(animalCopy.name);    } catch (CloneNotSupportedException e) {        e.printStackTrace();    }}
按着上面讲的,打印结果应该都是dog才对,因为我们并没有对String进行clone
原因是String是
不可变对象(immutable)
以String为例,String是用来表示字符串的类,它并没有提供任何改变字符串属性的方法,也就是说:String实例所代表的字符串属性,绝对不会改变(引自java多线程设计模式第二章immutable pattern)

有了上面的解释,这里就好理解多了

String是不可变的,那下面这句话就是让animalCopy.name指向一个新的对象了

animalCopy.name = "dog";
两个动物的name指向不同的对象,所以结果也不一样
回头再看animal这个类,
如果它只有基本类型的属性和不可变类型的属性,或是是子对象生命周期内不会发生变化也不提供更改其方法的对象,那么只需浅clone就可以了。否则需要深clone
-------------------------------------------------------------
标记接口(tagging interface/marker interface)
标识接口是没有任何方法和属性的接口.
它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情.
使用标记接口的唯一目的是使得可以用instanceof进行类型查询
java.io.Serializable
未实现此接口的类将无法使其任何状态序列化或反序列化.
为保证 serialVersionUID 值跨不同 java 编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID 值.
java.lang.Cloneable
表明Object.clone()方法可以合法地对该类实例进行按字段复制.
实现此接口的类应该使用公共方法重写 Object.clone(它是受保护的).
如果在没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常.
java.util.RandomAccess
用来表明其支持快速(通常是固定时间)随机访问.
此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能.
java.rmi.Remote                          
Remote 接口用于标识其方法可以从非本地虚拟机上调用的接口.
任何远程对象都必须直接或间接实现此接口.

只有在“远程接口”(扩展 java.rmi.Remote 的接口)中指定的这些方法才可远程使用.

转贴请保留以下链接

本人blog地址

转载地址:http://tycti.baihongyu.com/

你可能感兴趣的文章
程序员失误造成服务停用3小时,只得到半月辞退补偿,发帖喊冤
查看>>
码农:很多人称我“技术”,感觉这是不尊重!纠正无果后果断辞职
查看>>
php程序员看过来,这老外是在吐糟你吗?看看你中了几点!
查看>>
为什么说程序员是“培训班出来的”就是鄙视呢?
查看>>
码农吐糟同事:写代码低调点不行么?空格回车键与你有仇吗?
查看>>
阿里p8程序员四年提交6000次代码的确有功,但一次错误让人唏嘘!
查看>>
一道技术问题引起的遐想,最后得出结论技术的本质是多么的朴实!
查看>>
985硕士:非科班自学编程感觉还不如培训班出来的,硕士白读了?
查看>>
你准备写代码到多少岁?程序员们是这么回答的!
查看>>
码农:和产品对一天需求,产品经理的需求是对完了,可我代码呢?
查看>>
程序员过年回家该怎么给亲戚朋友解释自己的职业?
查看>>
技术架构师的日常工作是什么?网友:搭框架,写公共方法?
查看>>
第四章 微信飞机大战
查看>>
九度:题目1008:最短路径问题
查看>>
九度Online Judge
查看>>
九度:题目1027:欧拉回路
查看>>
九度:题目1012:畅通工程
查看>>
九度:题目1017:还是畅通工程
查看>>
九度:题目1034:寻找大富翁
查看>>
第六章 背包问题——01背包
查看>>