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

时间:2009-01-16 19:32:13

标签: java object protected

关键字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

看看下面的例子:

public class Testclass {
  public Object getOne() throws CloneNotSupportedException {
    return this.clone();
  }
  public Object getTwo() throws CloneNotSupportedException {
    return ((Object) this).clone();
  }
}

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

Testclass.java:6: clone() has protected access in java.lang.Object
        return ((Object) this).clone();

我既不理解getTwo()无法编译的原因,也不理解java.lang.Object成员与getOne()成员的访问权限有何不同。

3 个答案:

答案 0 :(得分:16)

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

这是一个例子;假设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 成为a的类   声明受保护的成员 m 。访问   只允许在一个体内    C 的子类 S 。另外,如果Id   表示实例字段或实例   方法,然后:如果访问是由a   限定名称​​ Q.Id ,其中 Q 是    ExpressionName ,然后是访问权限   当且仅当类型允许时允许   表达式 Q S 或其子类   取值。如果访问是通过字段访问   表达式 E.Id ,其中 E 主要   表达式,或通过方法调用   表达式 E.Id(...),其中 E 是a   主要表达式,然后访问权限   当且仅当 E 的类型允许时   是 S S 的子类。

答案 1 :(得分:5)

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

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

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

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

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

答案 2 :(得分:1)

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

在getTwo()中虽然您正在访问Object.clone()和而不是 TestClass.clone()。为了使其工作,您必须具有对象的包级别访问权限,而不是错误。