views:

180

answers:

7

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?

A: 

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.

BalusC
If you create some method inside Y that receive any object of Y type and try to call abby() - everything will be ok.I tried it.
zeroed
Did the question/example say anything about adding a new method or did you invent it yourself? You shouldn't be doing that. The context really shouldn't go further than the question itself. Otherwise it's easy to say "yes" to all questions.
BalusC
But how can an instance call some method on another instance without a method? O_o
zeroed
Kid, truly it's **possible**, but you just have to answer the whole question with yes or no, not to suggest a solution which changes the answer of the question. You should really not invent/add more code which isn't covered by the sole question at all. That's the whole point of those kind of questions.
BalusC
In this case the question is confusing and should not be used on certification exam.I hope it is.
zeroed
I must say, the question sucks - or I don't get something, a native speaker would understand. The first part seems to be about visibility, and I can create somewhere in Y another Y and call abby(). According to your answer, this question is not at all about visibility, it's "does an object know every other instance due to some java magic?"
Zappi
A: 

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();
    }
}
Nate
A: 

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();
Rorick
+2  A: 

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."

Esko Luontola
+1  A: 

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.

starblue
A: 

Any way, have become a SCJP today! :)

zeroed
A: 

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).

Dean Povey