CloneNotSupportedException的解决方案
引入问题:
在一次测试clone方法时,D类Override了Object类的clone方法
public class D {private Integer A1;private Integer A2;public D() {}public D(Integer a1, Integer a2 {A1 = a1;A2 = a2;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
123456789101112131415161718
在测试类中执行clone方法报错了
public class Test5 {public static void main(String[] args) {D p = new D();D p2 = null;try {p2 = (D)p.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}System.out.println(p == p2);}}
12345678910111213141516
抛出了 CloneNotSupportedException
寻找原因:
既然是重写自Object的clone方法,那么去看看Object对该方法的定义:
protected native Object clone() throws CloneNotSupportedException;
1
其中对于异常抛出的描述如下:
Throws:
CloneNotSupportedException – if the object’s class does not support the Cloneable interface. Subclasses that override the clone method can also throw this exception to indicate that an instance cannot be cloned.
如果对象的class不实现Cloneable接口,子类重写clone方法会同样抛出异常表示实例不能被克隆;
哦?
那不意思就是说:你要不父类实现Cloneable接口,要不就子类实现Cloneable
两个测试代码:
测试1: 在父类上实现Cloneable接口
public class TestClone {public static void main(String[] args) throws CloneNotSupportedException {Father father = new Father();Father fatherClone = (Father) father.clone();Son son = new Son();Son sonClone = (Son) son.clone();System.out.println(father==fatherClone);System.out.println(son==sonClone);}}class Father implements Cloneable{private Integer f1;private Integer f2;public Father() {}public Father(Integer f1, Integer f2) {this.f1 = f1;this.f2 = f2;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Son extends Father{private Integer s1;private Integer s2;public Son() {}public Son(Integer s1, Integer s2) {this.s1 = s1;this.s2 = s2;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
不出意外,没有任何问题
测试2:在子类上实现Cloneable接口
public class TestClone {public static void main(String[] args) throws CloneNotSupportedException {
// Father father = new Father();
// Father fatherClone = (Father) father.clone();Son son = new Son();Son sonClone = (Son) son.clone();// System.out.println(father==fatherClone);System.out.println(son==sonClone);}}class Father {private Integer f1;private Integer f2;public Father() {}public Father(Integer f1, Integer f2) {this.f1 = f1;this.f2 = f2;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}class Son extends Father implements Cloneable{private Integer s1;private Integer s2;public Son() {}public Son(Integer s1, Integer s2) {this.s1 = s1;this.s2 = s2;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
执行父类的clone报错,但是执行子类的clone没得问题
SO:
哪个类的需要clone,就在那个类在重写clone方法,并且在那个类或者其父类中实现Cloneable接口
详细分析clone方法的实现:
由于Object的clone方法是native修饰的,也就是虚拟机内部实现的方法
根据Hotspot虚拟机定义,找到Object.c
为什么要实现Cloneable接口?
在JVM_Clone方法中有这样一段判断:
很明显,虚拟机给你抛出的异常
为什么会出现地址不同的情况?
很明显,直接在堆内存中执行allocate方法开辟新的对象空间
并返回一个 oop 对象,也就是对象描述的指针(指向对象的首地址)