每天进步一丢丢,连接梦与想
我们还年轻,但这不是你浪费青春的理由
克隆和复制
clone,有人称之为克隆,有人称之为复制,其实都是同一个东西
本文称之为"克隆",毕竟人家方法名叫"clone"
为什要用克隆
想一想,为什么需要克隆?为什么不重新new一个?道理很简单,目的是想要两个相同的对象,重新new一个还得自己重新赋值,太麻烦
如何克隆一个对象?
如果是个初学者,可能会这么写
public class Student { String name; public Student(String name) { super(); this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public static void main(String[] args){ Student stu1 = new Student("小明"); Student stu2 = stu1; } }
这确实是做了克隆,但只是克隆了引用变量
来验证一下
System.out.println("stu1:"+stu1.getName()+" stu2:"+stu2.getName()); System.out.println("stu1 == stu2 : "+(stu1 == stu2)); //改名字 stu1.setName("小张"); System.out.println("改名后 stu1:"+stu1.getName()+" stu2:"+stu2.getName());//输出stu1:小明 stu2:小明 stu1 == stu2 : true改名后 stu1:小张 stu2:小张
修改了stu1的名字后,stu2的名字也随着改变
可以看出,两个引用stu1
和stu2
指向同一个对象
如图
image
你需要的是这样的克隆?
回想一下,平时真正需要的是两个不同对象
Object类中的clone
先来看下clone的源码,在Object类中
/* Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object. The general intent is that, for any object x, the expression: 1) x.clone() != x will be true 2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements. 3) x.clone().equals(x) will be true, this is not an absolute requirement. */protected native Object clone() throws CloneNotSupportedException;
仔细看,它是个native方法,native方法是由非java语言实现的(因为java本身无法直接对操作底层进行访问和操作,需要通过其他语言实现)
注释主要说明了3点:
克隆对象和原对象不是同一个对象,占用不同的内存地址
克隆对象和原对象应该具有相同的类型,但它不是强制性的
克隆对象和原对象使用equals()方法比较应该是相等的,但它不是强制性的
因为每个类的基类都是Object,所以都有clone方法,但是它是protected,所以不能在类外访问
克隆一个对象,需要对clone重写
如何实现克隆
在说实现前,得区分下浅克隆和深克隆
浅克隆:原对象和克隆对象不同,但对象内的成员引用相同
深克隆:原对象和克隆对象不同,且对象内的成员引用也不同
不同:不是同一个对象,所占内存地址不同
成员引用:类中为引用类型的成员
以图说明,更形象些男孩比喻为一个类,电脑比喻为类中的成员引用
image
一个男孩拥有一台电脑,通过浅克隆后,成了两个男孩,但他们共享一台电脑
一个男孩拥有一台电脑,通过深克隆后,成了两个男孩,他们拥有各自的电脑
浅克隆
//学生类public class Student implements Cloneable{ private String name; private Integer age; private Bag bag; public Student(String name,Integer age,Bag bag) { this.name = name; this.age = age; this.bag = bag; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Bag getBag() { return bag; } public void setBag(Bag bag) { this.bag = bag; } @Override public Student clone(){ Student stu = null; try{ stu = (Student)super.clone(); } catch (CloneNotSupportedException e){ e.printStackTrace(); } return stu; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", bag=" + bag.getName() + '}'; } }
//背包类public class Bag { private String name; public Bag(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
//测试类public class Test { public static void main(String[] args){ Student stu1 = new Student("小明",25,new Bag("小明的背包")); Student stu2 = stu1.clone(); System.out.println("两对象是否相等"); System.out.println("stu1 == stu2 "+(stu1 == stu2)); System.out.println("stu1 "+stu1.toString()); System.out.println("stu2 "+stu2.toString()); System.out.println("对象内引用成员是否相等"); System.out.println("stu1.name == stu2.name "+ (stu1.getName() == stu2.getName())); System.out.println("stu1.age == stu2.age "+(stu1.getAge() == stu2.getAge())); System.out.println("stu1.bag == stu2.bag "+(stu1.getBag() == stu2.getBag())); } }//输出两对象是否是同一对象 stu1 == stu2 falsestu1 Student{name='小明', age=25, bag=小明的背包} stu2 Student{name='小明', age=25, bag=小明的背包} 对象内引用成员是否相等 stu1.name == stu2.name truestu1.age == stu2.age truestu1.bag == stu2.bag true
可看出,原对象和克隆对象不是同一对象
,克隆对象内的值与原对象相同;对象内引用成员相等,说明只做了引用克隆,不同引用指向同一对象
//改变stu1类中成员的值stu1.setName("小张"); stu1.setAge(18); stu1.getBag().setName("小张的背包"); System.out.println("stu1 "+stu1.toString()); System.out.println("stu2 "+stu2.toString());//输出stu1 Student{name='小张', age=18, bag=小张的背包} stu2 Student{name='小明', age=25, bag=小张的背包}
作者:java从心
链接:https://www.jianshu.com/p/a820d0124bda
共同学习,写下你的评论
评论加载中...
作者其他优质文章