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()
给出了
我既不明白为什么getTwo()
不编译也不明白与getOne()
有什么区别(关于java.lang.Object
s 成员的访问)。
【问题讨论】:
很难相信我在查看Clonable
和 Object.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,其中 Q 是 ExpressionName,则访问为 当且仅当 表达式 Q 是 S 或 S。如果访问是通过字段访问 表达式 E.Id,其中 E 是 Primary 表达式,或通过方法调用 表达式 E.Id(. . .),其中 E 是 Primary 表达式,则访问为 当且仅当 E 的类型允许 是 S 或 S 的子类。
【讨论】:
请注意,该引用中的类可以访问同一包中的 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 的受保护方法如何免受子类的影响?的主要内容,如果未能解决你的问题,请参考以下文章