洛阳网站建设官网,百度广告价格,网站蜘蛛记录器 v1.2,微信h5页面制作免费获得好工作的秘密#xff1a;有效的准备面试。在开始之前#xff0c;我们先来看以下代码存在什么问题#xff1f;class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {// 等号赋值#xff08; 基本类型#xff09;int number 6… 获得好工作的秘密有效的准备面试。在开始之前我们先来看以下代码存在什么问题class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {// 等号赋值 基本类型int number 6;int number2 number;// 修改 number2 的值number2 9;System.out.println(number number);System.out.println(number2 number2);// 等号赋值对象Dog dog new Dog();dog.name 旺财;dog.age 5;Dog dog2 dog;// 修改 dog2 的值dog2.name 大黄;dog2.age 3;System.out.println(dog.name dog.age 岁);System.out.println(dog2.name dog2.age 岁);}
}
程序执行结果number6
number29
大黄3岁
大黄3岁
可以看出如果使用等号复制时对于值类型来说彼此之间的修改操作是相对独立的而对于引用类型来说因为复制的是引用对象的内存地址所以修改其中一个值另一个值也会跟着变化原理如下图所示因此为了防止这种问题的发生就要使用对象克隆来解决引用类型复制的问题。1浅克隆默认的 clone() 方法为浅克隆代码如下class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {Dog dog new Dog();dog.name 旺财;dog.age 5;// 克隆Dog dog3 (Dog) dog.clone();dog3.name 小白;dog3.age 2;System.out.println(dog.name dog.age 岁);System.out.println(dog3.name dog3.age 岁);}
}
class Dog implements Cloneable {public String name;public int age;Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
程序执行结果旺财5岁
小白2岁
可以看出使用克隆就可以解决引用类型复制的问题了原理如下图所示以上这种复制方式叫做浅克隆。浅克隆的实现条件需要克隆的对象必须实现 Cloneable 接口并重写 clone() 方法即可实现对此对象的克隆。然而使用浅克隆也会存在一个问题请参考以下代码。class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {DogChild dogChild new DogChild();dogChild.name 二狗;Dog dog4 new Dog();dog4.name 大黄;dog4.dogChild dogChild;Dog dog5 (Dog) dog4.clone();dog5.name 旺财;dog5.dogChild.name 狗二;System.out.println(dog name 4dog4.name);System.out.println(dog name 5dog5.name);System.out.println(dog child name 4dog4.dogChild.name);System.out.println(dog child name 5dog5.dogChild.name);}
}
class Dog implements Cloneable {public String name;public DogChild dogChild;Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
class DogChild {public String name;
}
程序执行结果dog name 4大黄
dog name 5旺财
dog child name 4狗二
dog child name 5狗二
也就是说浅克隆只会复制对象的值类型而不会复制对象的引用类型。原因如下图所示要处理引用类型不被复制的问题就要使用到深克隆。2深克隆定义深克隆就是复制整个对象信息包含值类型和引用类型。深克隆的实现方式通常包含以下两种。序列化实现深克隆先将原对象序列化到内存的字节流中再从字节流中反序列化出刚刚存储的对象这个新对象和原对象就不存在任何地址上的共享这样就实现了深克隆。所有引用类型都实现克隆要复制对象的所有引用类型都要实现克隆所有对象都是复制的新对象从而实现了深克隆。深克隆实现方式一序列化实现思路先将要拷贝对象写入到内存中的字节流中然后再从这个字节流中读出刚刚存储的信息作为一个新对象返回那么这个新对象和原对象就不存在任何地址上的共享自然实现了深拷贝。请参考以下代码class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {BirdChild birdChild new BirdChild();birdChild.name 小小鸟;Bird bird new Bird();bird.name 小鸟;bird.birdChild birdChild;// 使用序列化克隆对象Bird bird2 CloneUtils.clone(bird);bird2.name 黄雀;bird2.birdChild.name 小黄雀;System.out.println(bird name: bird.name);System.out.println(bird child name: bird.birdChild.name);System.out.println(bird name 2: bird2.name);System.out.println(bird child name 2: bird2.birdChild.name);}
}
class CloneUtils {public static T extends Serializable T clone(T obj) {T cloneObj null;try {//写入字节流ByteArrayOutputStream bo new ByteArrayOutputStream();ObjectOutputStream oos new ObjectOutputStream(bo);oos.writeObject(obj);oos.close();//分配内存,写入原始对象,生成新对象ByteArrayInputStream bi new ByteArrayInputStream(bo.toByteArray());//获取上面的输出字节流ObjectInputStream oi new ObjectInputStream(bi);//返回生成的新对象cloneObj (T) oi.readObject();oi.close();} catch (Exception e) {e.printStackTrace();}return cloneObj;}
}
程序执行结果bird name:小鸟
bird child name:小小鸟
bird name 2:黄雀
bird child name 2:小黄雀
深克隆实现方式二所有引用类型都实现克隆class SerializableTest {public static void main(String[] args) throws IOException, ClassNotFoundException {ParrotChild parrotChild new ParrotChild();parrotChild.name 小鹦鹉;Parrot parrot new Parrot();parrot.name 大鹦鹉;parrot.parrotChild parrotChild;// 克隆Parrot parrot2 (Parrot) parrot.clone();parrot2.name 老鹦鹉;parrot2.parrotChild.name 少鹦鹉;System.out.println(parrot name: parrot.name);System.out.println(parrot child name: parrot.parrotChild.name);System.out.println(parrot name 2: parrot2.name);System.out.println(parrot child name 2: parrot2.parrotChild.name);}}
class Parrot implements Cloneable {public String name;public ParrotChild parrotChild;Overrideprotected Object clone() throws CloneNotSupportedException {Parrot bird (Parrot) super.clone();bird.parrotChild (ParrotChild) parrotChild.clone();return bird;}
}
class ParrotChild implements Cloneable {public String name;Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
程序执行结果parrot name:大鹦鹉
parrot child name:小鹦鹉
parrot name 2:老鹦鹉
parrot child name 2:少鹦鹉
相关面试题使用克隆有什么好处好处包含以下几点使用方便假如要复制一个对象但这个对象中的部分属性已经被修改过了如果不使用克隆的话需要给属性手动赋值相比克隆而已麻烦很多性能高查看 clone 方法可以知道它是 native 方法native 方法是原生函数使用操作系统底层的语言实现的因此执行效率更高隔离性克隆可以确保对象操作时相互隔离。clone() 源代码如下图浅克隆和深克隆有什么区别答区别主要在对引用类型的复制上具体信息如下。浅克隆只会复制对象的值类型而不会复制对象的引用类型深克隆复制整个对象包含值类型和引用类型。如何实现浅克隆答克隆的对象实现 Cloneable 接口并重写 clone() 方法就可以实现浅克隆了。以下代码执行的结果是import java.util.Arrays;
class CloneTest {public static void main(String[] args) throws CloneNotSupportedException {CloneObj cloneObj new CloneObj();cloneObj.name 老王;cloneObj.age 30;cloneObj.sistersAge new int[]{18, 19};CloneObj cloneObj2 (CloneObj) cloneObj.clone();cloneObj2.name 磊哥;cloneObj2.age 33;cloneObj2.sistersAge[0] 20;System.out.println(cloneObj.name | cloneObj2.name);System.out.println(cloneObj.age | cloneObj2.age);System.out.println(Arrays.toString(cloneObj.sistersAge) | Arrays.toString(cloneObj2.sistersAge));}
}
class CloneObj implements Cloneable {public String name;public int age;public int[] sistersAge;Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
答执行结果如下。老王|磊哥
30|33
[20, 19]|[20, 19]
深克隆如何实现有几种实现方式答一般实现方式有以下两种通过序列化实现深克隆序列化实现方式Java 原生序列化、JSON 序列化、Hessian 序列化所有引用类型都实现克隆从而实现深克隆。为什么不能直接使用 Object 的 Clone 方法还要重写 clone() 方法之后才能实现克隆虽然所有类都是 Object 的子类但因为 Object 中的 clone() 方法被声明为 protected 访问级别所以非 java.lang 包下的其他类是不能直接使用的。因此要想实现克隆功能就必须实现 Cloneable并重写 clone() 方法才行。序列化可不可以实现深克隆实现的原理是什么答先将原对象序列化到内存的字节流中再从字节流中反序列化出刚刚存储的对象这个新对象和原对象就不存在任何地址上的共享这样就实现了深克隆。是否可以自定义序列化过程覆盖 Java 中的默认序列化过程答可以在 Java 中默认序列化一个对象需要调用 ObjectOutputStream.writeObject(saveThisObject) 和 ObjectInputStream.readObject() 读取对象你可以自定义这两个方法从而实现自定义序列化的过程。需要注意的重要一点是记得声明这些方法为私有方法以避免被继承、重写或重载。以上内容来自《Java面试全解析》【End】关注下方二维码订阅更多精彩内容。