为何无法在子类中访问Object类的protected方法clone()?
为什么无法直接调用Object类的protected clone()方法?
这是个非常典型的Java访问权限误区,很多刚接触克隆机制的开发者都会碰到这个问题,我来给你把底层逻辑讲透:
先搞懂protected权限的真实规则
你可能误以为「子类可以随便访问父类的protected方法」,但Java对protected的权限控制其实有更细的限制:
- 你可以访问自己实例中继承自父类的protected方法
- 同包类可以访问任何同包实例的protected方法
- 但不同包的子类,或者非子类的同包类,不能通过其他子类的实例去访问父类的protected方法
回到你的代码场景:
Test类和Test2类是同包,但Test不是Test2的子类- 你在
Test的main方法里,调用的是Test2实例的clone()方法——这个方法本质是Object类的protected方法 - 对于
Test来说,它虽然是Object的子类,但它只能调用自己实例的clone(),不能调用另一个Object子类(Test2)实例的clone(),因为跨了实例所属的子类类型,权限不允许
为什么实现Cloneable还不够?
Cloneable只是一个标记接口,它的作用仅仅是告诉Object的clone()方法:「这个类允许被克隆」,如果没有实现它,调用clone()会抛出CloneNotSupportedException。但它完全不会改变clone()方法的访问权限——Object的clone()依然是protected。
解决方法
方法1:在Test2中重写clone()并改为public
这是最标准的做法,重写后对外开放克隆能力:
class Test2 implements Cloneable { @Override public Object clone() throws CloneNotSupportedException { // 调用父类的clone实现 return super.clone(); } }
然后在Test类中调用时需要处理异常(要么main方法加throws CloneNotSupportedException,要么用try-catch包裹):
public class Test { public static void main(String[] args) throws CloneNotSupportedException { Test2 c1 = new Test2(); Test2 c2 = (Test2) c1.clone(); // 现在可以正常调用了 } }
方法2:提供自定义的克隆方法(封装clone())
如果不想把clone()暴露为public,可以在Test2里写一个自定义的public方法,内部调用clone():
class Test2 implements Cloneable { public Test2 createCopy() throws CloneNotSupportedException { return (Test2) this.clone(); } }
然后Test类里调用这个方法:
public class Test { public static void main(String[] args) throws CloneNotSupportedException { Test2 c1 = new Test2(); Test2 c2 = c1.createCopy(); } }
内容的提问来源于stack exchange,提问作者Denys_newbie
相关产品推荐
相关产品推荐

