My confusion arose from a discussion in this thread. I've read quite a few links (see below), notably c2.com and the JLS (20.1) and found no answer. I hope it's hidden somewhere in the JLS and I'm just not finding it. I'm using JDK 1.5.0_01b.
Here's a summary of the issue.
public class A
public class B extends A
B's methods can call A's protected methods on A references, as expected.
B's methods can call Object's protected methods on B references, as expected.
B's methods cannot call Object's protected methods on A references. (compile error: "foo() has protected access in java.lang.Object")
Unless I've made some other mistake, the protected methods in Object are "extra protective." How is this so? If there's some magic compiler trickery, shouldn't the JLS mention it? BTW, static and instance methods have the same results.
As a further test I put in another level in inheritence (class C extends B) and added a protected method to A itself. Yet C's methods can call A's protected method on A references but still not Object's protected methods.
Note that I'm speaking of calling methods on A references -- not on the "this" object. The latter case works fine.
Here are the three classes to see for yourself.Here are some of the links I've checked:
Object seems different from your other classes only because it's in a different package from A, B, and C. Remember that a group of classes can access each other's protected methods regardless of any inheritance relationships if they're all in the same package.
The rule for protected method access is a little bit odd when you first hear it. The JLS explains it here.
Imagine that your classes A, B, and C are in three separate packages, and A defines a protected member foo(), B subclasses A, and C subclasses B. The rule is that B is allowed to call foo() only on instances of B or C and not on instances of A. This is stated in JLS 18.104.22.168:
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.
In your scenario, then, you should now be able to understand why B can call clone() on instances of B(), but not on instances of A. B can call A's protected method copy() on instances of A only because B and A are in the same package; if you moved A and B to separate packages, B's ability to do this would go away.
Thank you! Yes, that absolutely answers my question. Indeed, I separated all three classes, and it behaves as you stated.The funny thing is that I was actually surprised that I could call protected methods through the references, that I am aware of the strangeness of protected with regard to packages, and yet I didn't connect the two. Admittedly, whenever the package/protected dichotomy comes up, I always need to look it up to get the exact rules straight. Maybe this will make it stick in my brain.