Question

Is the protected variable of a parentObject be accessed from any child Object? or can be accessed only by only the particular childObject? I have a scenario which clearly expresses my doubt.

I have two classes ParentClass and ChildClass. ParentClass is parent of ChildClass. I have a protected variable in ParentClass named protVar. It is of type Object. Then, I create two Objects like the following.

ParentClass p1 = new ParentClass();
ChildClass c1 = new ChildClass();
c1.callMethod(p1); // Here I want to access protected variable of p1 which is a separate object and Not initialized within c1 as super()

Now will I be able to access the protVar of p1 from c1?

Was it helpful?

Solution

Disclaimer: the answer is copied from my answer of another question. However no answer from that question is accepted. I believe it also suit this question therefore I am copying the content with some minor editing to here.

protected is a bit interesting in Java. Although we always says "protected" give access to subclass of different package, it is not the whole picture.

For example, if you have Child extending Parent, and there is a protected member in Parent. What you can do in Child is to access that protected member of Child, but not even that protected member of Parent. Sounds a bit strange right although they sounds the same thing?

Quoted from Core Java 9th Edition:

However, the Manager class methods can peek inside the hireDay field of Manager objects only, not of other Employee objects. This restriction is made so that you can’t abuse the protected mechanism by forming subclasses just to gain access to the protected fields

(class Manager extends Employee, and there is a hireDay protected member in Employee, and Manager and Employee are located in DIFFERENT package)

For example,

public class Manager extends Employee {
    // accessing protected member of itself
    public void foo1() {   
        System.out.println("" + this.hireDay);  // OK
    }

    // access protected member of instance of same type
    public void foo2(Manager manager) {  
        System.out.println("" + manager.hireDay);  // OK
    }

    // access protected member of instance of super-class
    public void foo3(Employee employee) {
        System.out.println("" + employee.hireDay);  // NOT ALLOWED!
    }
}

Which means, protected member allow child class from another package to access through reference of that child class (either this, or another reference that is-a child class)

And, be specific to OP's answer: if callMethod is declared in ChildClass, then NO, you cannot do it and it will not even compile. However if callMethod is declared in ParentClass then everything is fine, because it is simply ParentClass accessing protected member of a ParentClass instance.


Update:

Given criticisms in comment, I think it worth to go to JLS to see what it say:

(Quoted from http://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6.2.1 about Access to a protected Member, second bullet)

If the access is by a field access expression E.Id, or a method invocation expression E.Id(...), or a method reference expression E :: Id, where E is a Primary expression (§15.8), then the access is permitted if and only if the type of E is S or a subclass of S

This is essentially what I was trying to deliver in the answer:

Within Manager class, manager.hireDay works because manager is a primary expression, and the access is permitted because type of manager is Manager or subclass of Manager.

So, based on JLS, why manager.hireDay works DOES have relationship with type of manager (being the same type).

OTHER TIPS

Yes, a derived class can access a protected variable in a base class via both 'super' and another reference to the base class.

EDIT It should be noted that I am here assuming the same package as you didn't state anything about different packages. The rules are different otherwise.

If your child class and Parent class in same package than you can access this object directly [If you wish], Otherwise you have two option.
1 - Create a public getter method in Parent class and access your protected field using that method
2 - Inside child class fetch the Parent protected field using reflection like given below

public void callMethod(ParentClass o) {
    try {
        Field f = o.getClass().getDeclaredField("protVar");
        f.setAccessible(true);
        Object value = f.get(o);
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

Even though the question is old , I am trying my best to explain , since this is a fairly common question for java newbies.

Consider Employee class in package p1.

package p1;
public class Employee{
    protected String hireDay = "hireday";
}

Manager extends Employee and is in a different package.

package p2;
public class Manager extends p1.Employee {
 //now even Manager class has hireDay protected variable that was defined in Employee class.
 //Since Manager class has protected variable hireDay , for any manager m1 , we can access hireDay as m1.hireDay ONLY within package p2.
}

Enterprenur class extends Manager and is in package p3.

package p3;
public class Enterpreneur extends p2.Manager{

    //now  Enterpreneur class has inherited hireDay protected variable that  Employee class had. (see comments in Employee class.)
 //Since Enterpreneur class has protected variable hireDay , for any Enterpreneur e , we can access hireDay as e.hireDay ONLY within package p3.



    //the following will work because using Enterpreneur reference e , we can access e.hireday within package p3 , this has nothing to do with
    //the fact that right now our code is present in Enterpreneur class , like the other answer said. Note the method is static.
    public static void printhireDay(Enterpreneur e){
        System.out.println("hireday is :" + e.hireDay);
    }

    //this will work because using this reference we can only access protected variable in the same class(Enterpreneur) or in a subclass.
    public void printhireDay(){
        System.out.println("hireday is :" + this.hireDay);
    }

    // This shouldn't work because using manager reference , we can only access protected field within package p2.
    /* public printhireDay(Manager m){
        System.out.println("hireday is :" + m.hireDay)
    }*/
}

Now within the root package , we have this class to test.

public class HelloWorld{

     public static void main(String []args){
        p3.Enterpreneur e = new p3.Enterpreneur();
        //both of these work.
        e.printhireDay();
        //printing by passing the reference e.
        p3.Enterpreneur.printhireDay(e);


     }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top