大家好,我是九神。这是互联网技术岗的分享专题,废话少说,进入正题:
61.为什么要应用克隆?
想对一个对象进行解决,又想保留原有的数据进行接下来的操作,就须要克隆了,Java语言中克隆针对的是类的实例。
62.如何实现对象克隆?
有两种形式:
1). 实现Cloneable接口并重写Object类中的clone()办法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,能够实现真正的深度克隆,代码如下:
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class UtilDemo { private UtilDemo() { throw new AssertionError(); } @SuppressWarnings("unchecked") public static <T extends Serializable> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 阐明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close办法没有任何意义 // 这两个基于内存的流只有垃圾回收器清理对象就可能开释资源,这一点不同于对外部资源(如文件流)的开释 } }
上面是测试代码:
import java.io.Serializable; /** * 学生 * @author 酱油君 * */ class Student implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // 姓名 private int age; // 年龄 private Teacher teacher; // 老师 public Person(String name, int age, Car car) { this.name = name; this.age = age; this.teacher = teacher; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Teacher getTeacher() { return teacher; } public void setTeacher(Teacher teacher) { this.teacher = teacher; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", teacher=" + teacher + "]"; } } /** * 老师类 * @author 酱油君 * */ class Teacher implements Serializable { private static final long serialVersionUID = -5713945027627603702L; private String teacherName; // 老师名称 private String skill; // 老师技能 public Teacher(String teacherName, String skill) { this.teacherName = teacherName; this.skill = skill; } public String getTeacherName() { return teacherName; } public void setTeacherName(String teacherName) { this.teacherName = teacherName; } public int getSkill() { return skill; } public void setSkill(String skill) { this.skill = skill; } @Override public String toString() { return "Teacher [teacherName=" + teacherName + ", skill=" + skill + "]"; } } class CloneTest { public static void main(String[] args) { try { Student s1 = new Student("郭靖", 33, new Teacher("黄蓉", "黯然销魂掌")); Student s2 = UtilDemo.clone(s1); // 深度克隆 s2.getTeacher().setSkill("打狗棒法"); // 批改克隆的Student对象s2关联的老师对象的技能属性 // 原来的Student对象s1关联的老师不会受到任何影响 // 因为在克隆Student对象时其关联的老师对象也被克隆了 System.out.println(s1); } catch (Exception e) { e.printStackTrace(); } } }
留神:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,能够查看出要克隆的对象是否反对序列化,这项查看是编译器实现的,不是在运行时抛出异样,这种是计划显著优于应用Object类的clone办法克隆对象。让问题在编译的时候裸露进去总是好过把问题留到运行时。
63.深拷贝和浅拷贝区别是什么?
深拷贝是将对象及值复制过去,两个对象批改其中任意的值另一个值不会扭转,这就是深拷贝(例:JSON.parse()和JSON.stringify(),然而此办法无奈复制函数类型)
浅拷贝只是复制了对象的援用地址,两个对象指向同一个内存地址,所以批改其中任意的值,另一个值都会随之变动,这就是浅拷贝(例:assign())
文章转载自:
经典Java面试题的答案——对象拷贝