帮助理解受保护方法的问题

发布于 2024-08-21 01:26:45 字数 645 浏览 7 评论 0原文

我正在阅读2005 年 4 月的《Sybex Complete Java 2 认证学习指南》 (ISBN0782144195)。本书适合想要通过java认证的java开发人员。

在了解访问修饰符(以及其他修饰符)一章之后,我发现了以下问题(#17):

正确或错误:如果类 Y 扩展 X班,两个班在 不同的包,并且 X 类有一个 受保护的方法称为 abby(),然后 Y 的任何实例都可以调用 abby() Y 的任何其他实例的方法。

这个问题让我有点困惑。

据我所知,您可以在同一类(或子类)的任何变量上调用受保护的方法。您不能在层次结构中比您更高的变量上调用它(例如您实现的接口)。

例如,您不能仅仅因为继承任何对象而克隆它。

但这些问题没有提到变量类型,只提到实例类型。

我有点困惑,回答“是”。

书上的答案是

错误。从不同包中的超类继承受保护方法的对象可以在其自身上调用该方法,但不能在同一类的其他实例上调用该方法。

这里没有关于变量类型的内容,只有关于实例类型的内容。

这很奇怪,我不明白。

有人能解释一下这是怎么回事吗?

I'm reading Sybex Complete Java 2 Certification Study Guide April 2005 (ISBN0782144195). This book is for java developers who wants to pass java certification.

After a chapter about access modifiers (along with other modifiers) I found the following question (#17):

True or false: If class Y extends
class X, the two classes are in
different packages, and class X has a
protected method called abby(), then
any instance of Y may call the abby()
method of any other instance of Y.

This question confused me a little.

As far as I know you can call protected method on any variable of the same class (or subclasses). You cannot call it on variables, that higher in the hierarchy than you (e.g. interfaces that you implement).

For example, you cannot clone any object just because you inherit it.

But the questions says nothing about variable type, only about instance type.

I was confused a little and answered "true".

The answer in the book is

False. An object that inherits a protected method from a superclass in a different package may call that method on itself but not on other instances of the same class.

There is nothing here about variable type, only about instance type.

This is very strange, I do not understand it.

Can anybody explain what is going on here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

脱离于你 2024-08-28 01:26:46

正确或错误:如果类 Y 扩展类 X,这两个类位于不同的包中,并且类 X 有一个名为 abby() 的受保护方法,则 Y 的任何实例都可以调用任何其他实例的 abby() 方法Y 的。

“错误。从不同包中的超类继承受保护方法的对象可以在其自身上调用该方法,但不能在同一类的其他实例上调用该方法”。

让我们把它写下来,就像 BalusC 所做的那样,并向 Y 添加一个调用 Y 的任何其他实例的 abby() 的方法:

package one;
public class X {
    protected void abby() {
    }
}

package other;
import one.X;
public class Y extends X {
    public void callAbbyOf(Y anyOther) {
        anyOther.abby();
    }
}

Y 可以调用它所要访问的任何 Y 实例的 abby() 方法。有参考。 所以书中的答案是明显错误的。Java 没有特定于实例的作用域(与具有实例私有作用域的 Scala 不同)。

如果我们试着仁慈一点,也许问题的意思是“Y的任何其他实例”,它可以访问恰好在内存中的Y的任何实例的方法吗? > - 这是不可能的,因为 Java 没有直接内存访问。但在这种情况下,这个问题的措辞非常糟糕,您甚至可以回答:“错误。您不能在不同 JVM 上的实例、已被垃圾收集的实例或已死亡的 JVM 上的实例上调用方法。”一年前等等。”

True or false: If class Y extends class X, the two classes are in different packages, and class X has a protected method called abby(), then any instance of Y may call the abby() method of any other instance of Y.

"False. An object that inherits a protected method from a superclass in a different package may call that method on itself but not on other instances of the same class".

Let's write that down, as BalusC did, and add to Y a method which calls the abby() of any other instance of Y:

package one;
public class X {
    protected void abby() {
    }
}

package other;
import one.X;
public class Y extends X {
    public void callAbbyOf(Y anyOther) {
        anyOther.abby();
    }
}

It is possible for Y to call the abby() method of any instance of Y to which it has a reference. So the answer in the book is blatantly wrong. Java does not have instance-specific scopes (unlike for example Scala which has an instance-private scope).

If we try to be merciful, maybe the question meant by saying "any other instance of Y" that can it access the method of any instance of Y which happens to be in memory - which is not possible, because Java does not have direct memory access. But in that case the question is so badly worded, that you could even answer: "False. You can not call methods on instances which are on a different JVM, or instances which have been garbage collected, or instances on a JVM which died one year ago etc."

盛夏尉蓝 2024-08-28 01:26:46

来自Java 语言规范

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 的子类时才允许访问。

因此受保护的成员在 S 的所有实例中都是可访问的,并且答案在您的 .书是错的。

From The Java Language Specification:

6.6.2.1 Access to a protected Member

Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:

  • If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.
  • If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.

So the protected member is accessible in all instances of S, and the answer in your book is just wrong.

娇妻 2024-08-28 01:26:46

这个问题的措辞似乎很糟糕 - 并询问了一个非常罕见的边缘情况(我什至不确定 SCJP 测试是否涵盖了这种情况)。它的措辞方式使您的答案正确,而给出的答案不正确。编码类似的构造并轻松运行它证明了这一点......

package inside;

public class Base {

    private String name;

    public Base(String name)  {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    protected String abby(String name) {
        String old = this.name;
        this.name = name;
        return old;
    }
}




package outside;
import inside.Base;

public class Another extends Base {

    public Another(String name) {
        super(name);
    }

    public String setAnother(Another another, String hack) {
        return another.abby(hack);
    }

    public static void doCrazyStuff() {
        Another one = new Another("one");
        Another two = new Another("two");

        one.abby("Hi one"); 
        two.abby("Hi two");
        one.setAnother(two, "Hi two from one");

        System.out.println("one = " + one.getName());
        System.out.println("two = " + two.getName());

    }

    public static void main(String[] args) {
        Another.doCrazyStuff();
    }
}

That question seems badly worded - and asks about a very rare edge case (that I'm not even sure is covered on the SCJP test). The way that it's worded makes your answer correct and the given answer incorrect. Coding a similar construct and running it easily proves this...

package inside;

public class Base {

    private String name;

    public Base(String name)  {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    protected String abby(String name) {
        String old = this.name;
        this.name = name;
        return old;
    }
}




package outside;
import inside.Base;

public class Another extends Base {

    public Another(String name) {
        super(name);
    }

    public String setAnother(Another another, String hack) {
        return another.abby(hack);
    }

    public static void doCrazyStuff() {
        Another one = new Another("one");
        Another two = new Another("two");

        one.abby("Hi one"); 
        two.abby("Hi two");
        one.setAnother(two, "Hi two from one");

        System.out.println("one = " + one.getName());
        System.out.println("two = " + two.getName());

    }

    public static void main(String[] args) {
        Another.doCrazyStuff();
    }
}
迷离° 2024-08-28 01:26:46

因为变量类型在这里无关紧要,直到它在问题上下文中“正常”为止。由于方法 abby() 属于 X(并且 Y 继承它),因此引用 Y 实例的变量类型并不重要声明:它可以是 XY。 abby() 可以访问,我们可以通过这两个变量调用它:

X myY1 = new Y();
myY1.abby();

Y myY2 = new Y();
myY2.abby();

Because variable type is irrelevant here till it is 'sane' in context of question. As method abby() belongs to X (and Y inherits it), it doesn't matter with what type variable referencing instance of Y is declared: it can be either X or Y. Be abby() accessible, we could call it through both variables:

X myY1 = new Y();
myY1.abby();

Y myY2 = new Y();
myY2.abby();
涙—继续流 2024-08-28 01:26:46

正确或错误:如果类 Y 扩展类 X,这两个类位于不同的包中,并且类 X 有一个名为 abby() 的受保护方法,则 Y 的任何实例都可以调用任何其他实例的 abby() 方法Y 的。

让我们来描绘一下。

X 类:

package one;
public class X {
    protected void abby() {}
}

Y 类:

package other;
public class Y extends X {}

测试用例:

public static void main(String[] args) {
    Y y1 = new Y();
    Y y2 = new Y();
    Y y3 = new Y();
    // ...
}

现在重读问题:y1 能否在 y2y3 上调用 abby() > 等?在 y1 上调用 abby() 也会调用 y2y3 等吗?

对于以后的问题,请尝试拿起笔和纸并按字面意思解释问题。这类模拟题有很多漏洞。

True or false: If class Y extends class X, the two classes are in different packages, and class X has a protected method called abby(), then any instance of Y may call the abby() method of any other instance of Y.

Let's depict it.

Class X:

package one;
public class X {
    protected void abby() {}
}

Class Y:

package other;
public class Y extends X {}

Testcase:

public static void main(String[] args) {
    Y y1 = new Y();
    Y y2 = new Y();
    Y y3 = new Y();
    // ...
}

Now reread the question: can y1 call abby() on y2, y3, etc? Will calling abby() on y1 also call those of y2, y3, etc?

For future questions, try to grab pen and paper and interpret the questions literally. There are pretty much holes in those kind of mock questions.

悸初 2024-08-28 01:26:46

我几乎可以肯定这个问题的意思是:

“Y 的任何实例都可以调用 X 的任何其他实例的 abbey() 方法”(不是 Y)。

那样的话,确实会失败。借用上面另一个答案中的示例,以下内容

package one;
public class X {
    protected void abby() {
    }
}

package other;
import one.X;
public class Y extends X {
    public void callAbbyOf(X anyOther) {
        anyOther.abby();
    }
}

将无法编译。

Java 语言规范在这里解释了原因: http: //java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.2

6.6.2.1 访问受保护的成员

设 C 为其中 a 的类
声明受保护的成员 m。使用权
只允许在一个体内
C 的子类 S。此外,如果 Id
表示实例字段或实例
方法,则:如果访问是通过
限定名 Q.Id,其中 Q 是
ExpressionName,那么访问就是
允许当且仅当类型
表达式 Q 是 S 或 S 的子类
S. 如果访问是通过现场访问进行的
表达式 E.Id,其中 E 是 Primary
表达式,或通过方法调用
表达式 E.Id(...),其中 E 是
主要表达式,则 访问为
允许当且仅当 E 的类型
是 S 或 S 的子类。
(强调我的)。

I am almost certain that the question meant:

"any instance of Y may call the abbey() method of any other instance of X" (not Y).

In that case it will indeed fail. To borrow the example from another answer above, the following:

package one;
public class X {
    protected void abby() {
    }
}

package other;
import one.X;
public class Y extends X {
    public void callAbbyOf(X anyOther) {
        anyOther.abby();
    }
}

will fail to compile.

The Java Language Specification explains why here: http://java.sun.com/docs/books/jls/third_edition/html/names.html#6.6.2

6.6.2.1 Access to a protected Member

Let C be the class in which a
protected member m is declared. Access
is permitted only within the body of a
subclass S of C. In addition, if Id
denotes an instance field or instance
method, then: If the access is by a
qualified name Q.Id, where Q is an
ExpressionName, then the access is
permitted if and only if the type of
the expression Q is S or a subclass of
S. If the access is by a field access
expression E.Id, where E is a Primary
expression, or by a method invocation
expression E.Id(. . .), where E is a
Primary expression, then the access is
permitted if and only if the type of E
is S or a subclass of S.
(emphasis mine).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文