首先作为我的第一篇博客,我还是很想写好,当做一个好的开头,原因是作为一位大二学信息工程的学生,我的编程实在拉跨,朋友建议将我学到的东西以博客的形式展现出来,慢慢提升自己。所以我就开始了。
接下来为大家带来我最近新学的知识,关于java里的clone的一些自己的理解。因此如果有什么错误的地方,欢迎大家的指正。
目录
一、clone()简介
clone顾名思义就是复制的意思,在java中,clone主要被用来创建对象的副本,它的默认行为是浅拷贝,如果想要实现深拷贝就需重写clone(),即在clone()中添加逻辑达到深拷贝的目的。为了更好理解clone(),我先说一下什么是浅拷贝和深拷贝。
二、浅拷贝、深拷贝
浅拷贝:浅拷贝是只复制对象本身,而不复制它的内部引用。换句话理解就是:浅拷贝指的是在拷贝对象时,新对象和原对象的引用指向相同的内存地址,因此它们共享相同的内部对象。这意味着,如果你对其中一个对象进行修改,可能会影响到另一个对象。
深拷贝:深拷贝是完完全全创建一个独立的新个体,除了它们的内容一样,所指的地址完全不一样。
浅拷贝可以理解为是同一个人,两个变量指向同一个对象,就比如:小猫叫咪咪还是喵喵都指的是猫,深拷贝可以理解为是两个一模一样的双胞胎,但是是两个单独的个体。
三、举例
接下来的例子是我的老师给我们布置的作业中,关于链表的一段代码,这段代码就使用了浅拷贝。
@Override
public SinglyLinkedList<E> clone() throws CloneNotSupportedException {
SinglyLinkedList<E> other = (SinglyLinkedList<E>) super.clone();
// 使用Object.clone()方法创建初始副本
if (size > 0) { // 需要独立的节点链
other.head = new Node<>(head.getElement(), null);
Node<E> walk = head.getNext(); // 遍历原始链表的剩余部分
Node<E> otherTail = other.head; // 记住最近创建的节点
while (walk != null) { // 创建存储相同元素的新节点
Node<E> newest = new Node<>(walk.getElement(), null);
//在每次迭代中,创建一个新节点 newest,它复制了当前遍历到的节点的元素值,但是它的下一个节点暂时设置为 null
otherTail.setNext(newest);
//将新节点 newest 添加到新链表的尾部,通过修改 otherTail 指向的节点的 next 属性来实现。
otherTail = newest;
//更新 otherTail 指针,使其指向新链表的最后一个节点,以便下一次迭代时可以将新节点连接到它后面。
walk = walk.getNext();
//将 walk 指针移动到原始链表的下一个节点,以便下一次迭代。
}
}
return other;
}
其中:1.@Override使用注解,表明要开始重写父类或者接口中的方法,此时编译器就会检查这部分的重写是否成功,若失败就会返回错误。
2.
public SinglyLinkedList<E> clone() throws CloneNotSupportedException
当没有实现重写clone()方法,则会抛出CloneNotSuppoortedException异常。
3.
SinglyLinkedList<E> other = (SinglyLinkedList<E>) super.clone();
这里将object类型强制转换为SinglyLinkedList<E>类型,原因是,当使用了clone()方法,则它返回的类型是object类型,我们只能使用他的方法,比如toString()、hashCode()等,如果不转换回我们的原类型,那么我们将不能使用我们原类型中定义的方法。
@Test
void testClone() {
try {
SinglyLinkedList<Integer> clonedList = list.clone();
assertEquals(list.size(), clonedList.size());
assertEquals(list.first(), clonedList.first());
assertEquals(list.last(), clonedList.last());
} catch (CloneNotSupportedException e) {
fail("Cloning should be supported.");
}
这段代码是对上段代码的测试代码,为了避免在修改代码时影响到源代码,导致测试失败,因此这里完全创建一个一模一样的副本用于测试,是深拷贝。