views:

112

answers:

3

Hi, I was curious to understand what's happening here.( a protected member being accessed outside the package through a subclass ) I know for classes outside the package, the subclass can see the protected member only through inheritance.

consider two packages - package1 and package2.

1) package1 - ProtectedClass.java


    package org.test.package1;

    public class ProtectedClass {

    protected void foo () {
        System.out.println("foo");
    }

}

2) package2 - ExtendsprotectedClass.java


package org.test.package2;

import org.test.package1.ProtectedClass;

public class ExtendsprotectedClass  extends ProtectedClass{

    public void boo() {
        foo(); // Correct.. since protected method is visible through inheritance
    }

    public static void main(String[] args){
        ExtendsprotectedClass epc = new ExtendsprotectedClass();
        epc.foo(); // Why is this working since its accessed through a reference. foo() should not be visible right ?
    }
}

3) package2 - UsesExtendedClass.java



    package org.test.package2; 
    public class UsesExtendedClass {
        public static void main(String[] args) {
            ExtendsprotectedClass epc = new ExtendsprotectedClass();
            epc.foo(); // Compilation Error- The method foo() from the type ProtectedClass is not visible
        }
    }

Its Understood that boo() method in ExtendsprotectedClass can access foo(), since protected member can be accessed through inheritance only.

My Query is, why is the foo() method working fine when accessed through a reference in main() method of ExtendsprotectedClass and will not work when accessed through reference in UsesExtendedClass.

+4  A: 

Code within the ExtendsprotectedClass class is allowed to access protected members of ProtectedClass via a reference of type ExtendsprotectedClass. From the JLS section 6.6.2:

A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.

and

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. [...]

UsesExtendedClass isn't reponsible for the implementation of ExtendsprotectedClass, hence the final call fails.

EDIT: The reasoning behind this is that protected access is designed to help subclasses implement the functionality they need, giving more access to the internals of the superclass than would normally be available. If that were available to all code, it would be pretty close to making the method public. Basically, the subclasses are trusted not to break encapsulation; they're given more capabilities within objects of their own type. The public API shouldn't expose those details, but the protected API can just for the purposes of giving subclasses more opportunities.

Jon Skeet
@Jon Thanks. I understand that class members of subclass can access protected members ( as indicated in `boo()` method ). But Was curious to know as to why it's allowed to access the protected member via a reference of the subclass, **ONLY** in subclass methods ? any rationale behind it ?
JWhiz
@JWhiz: Editing...
Jon Skeet
2) Works because because the protected method is accessed by a pointer of its own class. This should fail:<br> public static void ExtendsprotectedClass.main(String[] args){ ProtectedClass epc = new ExtendsprotectedClass(); //upcast <br> epc.foo(); // should be compilation error? <br> }
Markus Kull
@Jon:Totally agree that `protected` access is designed to help subclasses implement the functionality they need. That's why i had added a snippet of code `boo()` calling `foo()`.i.e subclass code can use the protected `foo()` or override `foo()` of the base class.understood. but what I'm still not getting is why is it allowed access directly through a reference `ExtendsprotectedClass epc = new ExtendsprotectedClass();epc.foo();`.It shouldn't had as in second case right?Any rationale on why is it allowing to access protected method `foo()` via a reference only in class implementing base class?
JWhiz
@JWhiz: Because it means that code within that class is able to work instances of itself easily - for things like comparison, static factory methods etc. It can be a real pain to write an instance method just for the sake of being able to get at a particular member. Again, the code of the subclass should know what it's doing.
Jon Skeet
@Jon : can you pls provide pointers to sample code where private/protected methods of same class are accessed via a reference of same class in which they are implementing base class. Accepted this as answer..
JWhiz
**PJ** : while accepting this as answer i observed that acceptance of answer and award of points to `Jon Skeet` is like adding a bottle of water to ocean. It still says `210K` :)
JWhiz
@JWhiz: Your "ExtendsProtection" class does exactly that. (For protected only, of course. Not private.)
Jon Skeet
@Jon : If u look at discussion below,by @fastcodejava, even private members can be accessed by references within same class.`public class Test {private String abcd = "abcd";public static void main(String[] args) {Test pc = new Test();pc.abcd = "efgh";System.out.println(pc.abcd);}}`*Why is access of private variable allowed through reference ?* Thats what caused curiosity in me as to why access to private members are allowed ? doesn't it violate the very purpose of making them private
JWhiz
@JWhiz: No, it doesn't - because it's private from *code in other classes*. In particular, not having access to private members would make it harder to check for equality between two instances and various other things. The purpose of private access is to hide implementation details. The code in question already *knows* the implementation details - because it's the same implementation! There's no more risk that that will cause harm to other objects of the same type than to `this`.
Jon Skeet
Thanks Jon. The discussion helped to understand the rationale behind it.
JWhiz
+1  A: 

I believe you've answered your own question; UsesExtendedClass does not inherit from ProtectedClass, and -- by definition -- "protected" members are accessible only in the class in which they are declared / defined or in a class that inherits from the one in which they are declared or defined.

Michael Aaron Safyan
@Michael - `by definition -- "protected" members are accessible only in the class in which they are declared / defined`. I don't quite agree with that as protected members are accessible from other classes within the same package without inheritance.
JWhiz
+2  A: 

It is working in the first case because it is being called from the same class even the method is being accessed through a reference. You could even call a private method of ExtendsprotectedClass through a reference in the same main method.

fastcodejava
@fastcodejava : Thanks. Now i see why its able to access it through reference. `+1` for it. But , It should not be allowed to call `private` methods through an Object reference right ? Doesn't this violate the very purpose of making it `private` ? Any specific reason for allowing to do so ?
JWhiz
@JWhiz the java access modifiers work at class and not at instance level. Because of that a private method is private to the class and not an instance. If private worked on instances you would have to make more variables and methods public if two instances have to interact. This would break encapsulation by making the implementation visible outside of the class.
josefx