欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

呐,码农呢,还是要多看点源码,喏->....

程序员文章站 2024-03-21 08:07:04
...

clone() 方法不可见, Oh No!!!

protected关键字

如果要是问我:protected 这个关键字,该如何理解?
重点需要提及:

  • java 限定访问范围的关键词
  • 修饰成员属性,会怎么样?
  • 修饰方法,会怎样?
  • 能否修饰类?
  • 他跟public, private,default有什么区别
  • 巴拉拉拉啊啦啦 …..

嗯~, 注意,这不是讲解java基础面试题,以上我是不会给你回答的 (任性,没办法~)。只是想说,看到 protected 我可能会从这些方面回答,这其中,有趣的是,我们知道 protected 是受保护的含义,但是到我们实际遇到问题的时候,会短路一会,然后,会, 哦~, 原来是这样!!!
您不信? 那就看看下面的情况 ~

clone()

最近,在梳理java知识点,在梳理到clone() 方法的时候,信手拈来 写了一段代码, 目的很简单。demo1 是DemoObject类型的变量, 想把demo1 “复制”一份给 demo2

伪代码
DemoObject demo1 = new DemoObject(param1, param2, ...paramN)
DemoObject demo2 = demo1.clone()

看到这里,请亲爱的你 关闭当前页面,花2分钟在IDE中快速写下, 看是否会遇到问题。

参考代码

public class DemoObject {
    int ver1;
    int ver2;
    int ver3;
    int ver4;

    String string1;
    String string2;
    String string3;
    String string4;

    DemoObject() {
    }

    DemoObject(int ver1, int ver2, int ver3, int ver4,
               String string1, String string2, String string3, String string4) {
        this.ver1 = ver1;
        this.ver2 = ver2;
        this.ver3 = ver3;
        this.ver4 = ver4;

        this.string1 = string1;
        this.string2 = string2;
        this.string3 = string3;
        this.string4 = string4;
    }
}
  • 以上代码是有瑕疵的,知道的同学,给我留言, 毫不留情 指出我的瑕疵,鞭策我成长 (感觉我有受虐强迫妄想症 ~)
public class JavaDay04 {
    JavaDay04() {
    }

    public static void main(String... args) {
        DemoObject demo1 = new DemoObject(1, 2, 3, 4, "11", "22", "33", "44");
        System.out.println(demo1);

        DemoObject demo2 = demo1.clone() // 有问题~
}

你会发现,clone 方法显示不了, 再打 equal 却可以。 嗯,问题来了,这是怎么回事?
IDE 也会提示 clone() has protected access in java.lang.Object

不要问我,看源码~

protected native Object clone() throws CloneNotSupportedException;

这里要明确 2点: 参考 Java 访问权限控制:你真的了解 protected 关键字吗?

  • (1)父类的protected成员 包内可见且对其子类可见;
  • (2)对于子类父类不同包情形,在子类中,只能访问自身从基类继承而来protected成员,而不能访问基类实例本身的protected成员。

针对我们具体的问题,分析如下:

  • 首先, DemoObject 继承自 Object, JavaDay04 继承自Object, DemoObject & JavaDay04 没有继承关系。 没有疑问! 按照 (1)说法,Object中的clone() 在DemoObject 以及JavaDay04中可以访问到, 没毛病 (不信? 自己手打验证下~)

  • 其次,按照 (2)说法,可以知道 DemoObject demo2 = demo1.clone() 无法通过编译,因为上述代码的范围是在JavaDay04类中,要想让demo1.clone()可见,需要在DemoObject中重写 clone方法。

DemoObject修改如下

public class DemoObject {
    .......

    ////////// 新增///////////////
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    } 
}

修改之后,在JavaDay04.java 中的调用 就可以访问 clone()

....
public static void main(String... args) {
        DemoObject demo1 = new DemoObject(1, 2, 3, 4, "11", "22", "33", "44");
        System.out.println(demo1);

        try {
            DemoObject demo2 = (DemoObject) demo1.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }

但是运行 直接crash

aaa@qq.com2503dbd3
java.lang.CloneNotSupportedException: DemoObject
    at java.lang.Object.clone(Native Method)
    at DemoObject.clone(DemoObject.java:53)
    at JavaDay04.main(JavaDay04.java:11)

来,还是来看源码。

Object.java 中 clone() 注释部分,有说明
     * The method {@code clone} for class {@code Object} performs a
     * specific cloning operation. First, if the class of this object does
     * not implement the interface {@code Cloneable}, then a
     * {@code CloneNotSupportedException} is thrown. 

注意,其中关键字 Cloneable ,要想顺利使用clone() , 需要让DemoObject实现 Cloneable 接口, 所有,DemoObject再次 修改如下。

public class DemoObject implements Cloneable {
}

修改JavaDay04

// 省略 ...
try {
            DemoObject demo2 = (DemoObject) demo1.clone();
            System.out.println(demo2);
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

打印结果为:

DemoObject@2503dbd3
DemoObject@4b67cf4d

小结

从clone() 方法,可以考察的点, 有如下几个:
1. protected 关键自的含义
2. clone() 该如何正确的使用

针对 1. 可以有如下的 示例图 给我们展示。
呐,码农呢,还是要多看点源码,喏->....
(图片来自: https://blog.csdn.net/justloveyou_/article/details/61672133)

至于 java clone() 默认是浅拷贝,还是深拷贝?本来是要继续解读一下的,但是发现有比我写的更好的文章,参考:
详解Java中的clone方法 – 原型模式

工具推荐

如果想看 Java 字节码同学,可以在Intellij 上安装一个ASM插件,如何安装,使用,你懂的。

祝 春安!
2018年03月31