【问题标题】:Why can clone set a private field on another object?为什么克隆可以在另一个对象上设置私有字段?
【发布时间】:2010-11-01 20:27:27
【问题描述】:

我正在学习 Java,我正在阅读的书中有以下关于克隆的示例。在clone() 中,我的第一个实例能够在新对象上设置缓冲区,即使缓冲区是private。似乎它应该要求该字段为 protected 才能工作。

为什么允许这样做? clone() 是否具有允许其访问 private 字段的特殊权限?

public class IntegerStack implements Cloneable {
    private int[] buffer;
    private int top;

    // ... code omitted ...

    @Override
    public IntegerStack clone() {
        try{
            IntegerStack nObj = (IntegerStack) super.clone();
            nObj.buffer = buffer.clone();
            return nObj;
        } catch (CloneNotSupportedException e)
        {
            throw new InternalError(e.toString());
        }
    }
}

【问题讨论】:

    标签: java private access-modifiers


    【解决方案1】:

    private 修饰符并不意味着只有同一个实例可以访问该字段;这意味着只有同一类的对象才能访问它。

    Java Language Specification§6.6, Access Control 中说:

    ...如果成员或构造函数被声明为私有,则当且仅当它出现在包含成员或构造函数声明的顶级类(§7.6) 的主体内时才允许访问。

    换句话说,类中的任何东西都可以随时访问它。甚至嵌套类也可以访问封闭类中的private 成员和构造函数,反之亦然。

    (你不是唯一一个误解它的人;查看this much-upvoted answer to "What is your longest-held programming assumption that turned out to be incorrect?

    【讨论】:

    • 谢谢!我也知道 PHP,所以我已经验证了 PHP 的 private 版本实际上以相同的方式工作。
    • 我认为大多数面向对象的语言都是这样工作的。我知道 C# 和 C++ 可以。显然 Ruby 和 VB6 有实例私有变量,而 Scale 可以做private[this],但这就是我所知道的另一种工作方式。 (我只从链接答案中的 cmets 了解 Ruby、VB6 和 Scala。)
    猜你喜欢
    • 2013-05-11
    • 2014-10-30
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    • 2022-11-11
    • 2020-07-29
    • 2013-03-31
    相关资源
    最近更新 更多