本文共 4129 字,大约阅读时间需要 13 分钟。
Object类是所有类的父类,所以它们都继承了Object类中的clone()方法,下面尝试使用下clone()。
class MyObject {} // 定义一个空类,Object类的子类public class CloneTest { // Object类的子类 public static void main(String[] args) { Object obj = new Object(); Object obj1 = obj.clone(); MyObject myObj = new MyObject(); MyObject myObj1 = myObj.clone(); // 错误: 不兼容的类型: Object无法转换为MyObject CloneTest cloneTest = new CloneTest(); CloneTest cloneTest1 = cloneTest.clone(); //错误: 不兼容的类型: Object无法转换为MyObject System.out.println("obj: "+obj+" obj1: "+obj1); System.out.println("myObj: "+myObj+" myObj1: "+myObj1); System.out.println("cloneTet: "+cloneTest+" cloneTest1: "+cloneTest1); }}
编译结果如下:
将后两行代码进行修改为
MyObject myObj = new MyObject();//MyObject myObj1 = myObj.clone(); // 错误: 不兼容的类型: Object无法转换为MyObjectObject myObj1 = myObj.clone(); CloneTest cloneTest = new CloneTest();//CloneTest cloneTest1 = cloneTest.clone(); //错误: 不兼容的类型: Object无法转换为MyObjectObject cloneTest1 = cloneTest.clone();
后面的两个错误就没了
在上面的代码中,主类CloneTest、空类MyObject都是Object类的子类,都继承了Object的clone()方法
1、cloneTest.clone()正常执行,而obj.clone()、myObj.clone()则不可见,说明:
子类CloneTest的对象可以访问自己类型的clone()方法, 却不能访问其父类Object、另一个子类myObj的clone()
也就是说,
不能在一个子类中访问另一个子类的对象的protected方法,尽管这两个子类继承自同一个父类;此外,子类不能访问父类的对象的protected方法,要通过自己类型的对象才能访问
即,只能通过自身实例(自身的引用)访问,不能通过父类实例(父类的引用)、其他子类实例(除非是该子类有重写clone()方法)
2、子类使用继承自父类的clone()方法时,返回的对象仍然是父类类型的对象
class MyObject { protected Object clone() throws CloneNotSupportedException { return super.clone(); }}public class CloneTest { public static void main(String[] args) throws CloneNotSupportedException { MyObject myObj = new MyObject(); Object myObj1 = myObj.clone(); CloneTest cloneTest = new CloneTest(); Object cloneTest1 = cloneTest.clone(); System.out.println("myObj: "+myObj+" myObj1: "+myObj1); System.out.println("cloneTet: "+cloneTest+" cloneTest1: "+cloneTest1); }}
在MyObject类中重写clone()方法,覆盖掉继承自父类的clone()方法,则编译通过,不再有因为protected引起的不可见问题
这时,子类CloneTest可以访问另一个子类MyObject的一个对象的clone()方法。
这时因为,在MyObject类中覆盖clone()方法时,MyObject类和CloneTest类在同一个包下,所以此protected方法对CloneTest类可见。
注意:main方法、重写的clone方法需要throws CloneNotSupportedException,否则编译时会出现下面的错误
但是,在这里虽然编译成功,当我们运行程序时依然会出错
查看Object的源码及文档,发现有这么一句话
The class Object
does not itself implement the interface Cloneable
, so calling the clone
method on an object whose class is Object
will result in throwing an exception at run time.
即,Object类中的clone()没有实现Cloneable接口,运行时就会抛出CloneNotSupportedException
而我们的子类MyObject在重写clone()时,也没有实现该接口,所以也会抛出异常
class MyObject implements Cloneable { protected Object clone() throws CloneNotSupportedException { return super.clone(); }}public class CloneTest implements Cloneable { public static void main(String[] args) throws CloneNotSupportedException { MyObject myObj = new MyObject(); Object myObj1 = myObj.clone(); CloneTest cloneTest = new CloneTest(); Object cloneTest1 = cloneTest.clone(); System.out.println("myObj: "+myObj+" myObj1: "+myObj1); System.out.println("cloneTet: "+cloneTest+" cloneTest1: "+cloneTest1); }}
在两个类的定义时写上implements Cloneable,再次编译、运行,这时运行就不会抛出CloneableNotSupportedException了
此外,可以发现
(1)调用clone()返回的对象是一个独立的副本,两个对象地址不同,属性相同。
(2)当我们直接输出两个对象时,尽管原对象的引用是子类类型、副本对象的引用是Object父类类型,输出结果显示对象是子类类型。也就是说,父类类型、子类类型的引用,都可以指向子类类型的对象。
(3)前面看到,clone()返回的对象依然是Object类型,因此,我们只需做强制转换,就可以转化成想要的类型了
MyObject myObj = new MyObject();//MyObject myObj1 = myObj.clone(); // 错误: 不兼容的类型: Object无法转换为MyObject//Object myObj1 = myObj.clone();MyObject myObj1 = (MyObject)myObj.clone(); CloneTest cloneTest = new CloneTest();//CloneTest cloneTest1 = cloneTest.clone(); // 错误: 不兼容的类型: Object无法转换为MyObject//Object cloneTest1 = cloneTest.clone();CloneTest cloneTest1 = (CloneTest)cloneTest.clone();
/*class MyObject implements Cloneable { protected Object clone() throws CloneNotSupportedException { return super.clone(); }}*/class MyObject implements Cloneable { public Object clone() { MyObject mo = null; try { mo = (MyObject)super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(); } return mo; }}