java.lang.Object 的受保护方法如何免受子类的影响?

Posted

技术标签:

【中文标题】java.lang.Object 的受保护方法如何免受子类的影响?【英文标题】:How are java.lang.Object's protected methods protected from subclasses? 【发布时间】:2010-10-01 21:16:48 【问题描述】:

关键字 protected 授予对同一包和子类 (http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html) 中的类的访问权限。

现在,每个类都有 java.lang.Object 作为超类 (http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html)。

因此我得出结论,每个类都可以访问java.lang.Object 的方法,即使它们是protected

看看下面的例子:

公共类测试类 公共对象 getOne() 抛出 CloneNotSupportedException 返回 this.clone(); 公共对象 getTwo() 抛出 CloneNotSupportedException return ((Object) this).clone();

虽然getOne() 编译得很好,但getTwo() 给出了

Testclass.java:6:clone() 在 java.lang.Object 中具有受保护的访问权限 return ((Object) this).clone();

我既不明白为什么getTwo() 不编译也不明白与getOne() 有什么区别(关于java.lang.Objects 成员的访问)。

【问题讨论】:

很难相信我在查看 ClonableObject.clone() 时也有同样的困惑 - 谢谢。 【参考方案1】:

如果您引用的表达式的编译时类型是您自己的类或子类,则您只能访问不同包中类型的受保护成员。 (其中“您的”类是包含代码的类。)您自己的类也必须是最初声明该方法的类型的子类。

这是一个例子;假设 Base 与所有其他类位于不同的包中:

package first;
public class Base

    protected void Foo() 


// Yes, each class is really in its own file normally - but treat
// all the classes below as being in package "second"

package second;
public class Child extends Base

    public void OtherMethod(Object x)
    
        ((Base) x).Foo(); // Invalid: Base is not Child or subclass
        ((Child) x).Foo(); // Valid: Child is Child
        ((GrandChild) x).Foo(); // Valid: GrandChild is subclass of Child
        ((OtherChild) x).Foo(); // Invalid: OtherChild is not Child or subclass
    


public class GrandChild extends Child 
public class OtherChild extends Base 

换句话说,它让您可以访问“与您相似的对象”的受保护成员。

详情在section 6.6.2 of the Java Language Specification:

protected 的成员或构造函数 可以从外部访问对象 声明它的包 仅由负责的代码 该对象的实现。

6.6.2.1 访问受保护成员

C 是一个类 声明了受保护的成员 m。使用权 只允许在一个体内 C 的子类 S。此外,如果 Id 表示实例字段或实例 方法,则:如果访问是由 限定名称 Q.Id,其中 QExpressionName,则访问为 当且仅当 表达式 QSS。如果访问是通过字段访问 表达式 E.Id,其中 EPrimary 表达式,或通过方法调用 表达式 E.Id(. . .),其中 EPrimary 表达式,则访问为 当且仅当 E 的类型允许 是 SS 的子类。

【讨论】:

请注意,该引用中的类可以访问同一包中的 any 类的受保护成员。 你打错了:
 public class Child extends Base   […]  
嗯。虽然您的 Javaspec 副本听起来很有说服力,但您的代码编译得非常好。似乎仍然与我的示例不同。 这是由于包业务 - 我修改了文本,说 Base 必须在不同的包中。我也会把它放在代码中。 啊,当然。否则访问受保护方法的封装方式仍然有效。【参考方案2】:

不同之处在于您访问 Object.clone() 的方式。只有通过同一包中的子类或类访问时才能访问克隆。在 getOne() 示例中,您将调用 this.clone()。这显然满足了从子类中的访问。

在 getTwo() 中,虽然您访问的是 Object.clone() 和 not TestClass.clone()。为了使其工作,您必须具有对您没有的对象的包级别访问权限,因此会出现错误。

【讨论】:

【参考方案3】:

当您说“((Object) this).clone()”时,您通过其超类 Object 访问了您自己的对象。您执行了到对象的扩展转换。然后代码尝试在 Object 上调用 clone。

但是,正如您所指出的,clone 是一种受保护的方法,这意味着只有当您的对象在同一个 java.lang 包中时,它才能访问 OBJECT 的 clone 方法。

当您说 this.clone 时,您的类扩展了 Object,因此可以通过受保护的类修饰符直接访问覆盖或使用克隆,因为继承。但这不会改变 Object 的实现。

通过说 ((Object) yourObject),你得到的东西只能通过 Object 类访问。只有 Object 类的公共方法可以在 java.lang 包之外访问,因此您会得到编译时异常,因为编译器知道这一点。

通过说 this.clone(),您正在调用对象的 clone 方法,该方法是通过 Object 继承得到的,并且现在可以被调用,因为它成为您自定义子类的一部分。

【讨论】:

你把保护和包保护混淆了。 我不这么认为:“当你说 this.clone 时,你的类扩展了 Object,因此可以通过受保护的类修饰符直接覆盖或使用克隆,因为继承” 我对这句话吹毛求疵:“但是,正如你所指出的,clone 是一种受保护的方法,这意味着只有当你的对象在同一个 java.lang 包中时,它才能访问 OBJECT 的克隆方法。”从表面上看,这听起来是错误的。但是让我重新考虑一下...... 好的,我想我现在明白了。 +1 让我思考。 对不起,mmyers。我的意思是你的类不能访问 Object 的 clone 方法,但它可以通过作为对象的子类来使用或覆盖它:它只能访问 Object 实现(阅读:使用 Object.clone(),而不是你的类。 clone()) 通过在同一个包中,即 java.lang.

以上是关于java.lang.Object 的受保护方法如何免受子类的影响?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Derived 内部调用 Base 实例中的受保护成员函数?

如何在同一个类的静态方法中访问类的受保护变量?

C++ 派生模板类:访问实例的受保护成员

清洁代码 - 以下划线开头的受保护方法的目的是什么?

为啥我不能在同一类的受保护方法中调用方法[重复]

无法访问子类中的受保护方法[重复]