12

关键字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()不编译也不明白java.lang.ObjectgetOne().

4

3 回答 3

16

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

这是一个例子;假设它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 {}

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

详细信息在Java 语言规范的第 6.6.2 节中

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

6.6.2.1 访问受保护成员

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

于 2009-01-16T19:47:05.127 回答
5

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

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

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

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

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

于 2009-01-16T19:46:47.827 回答
1

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

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

于 2009-01-16T19:51:03.717 回答