43

I have a class called A in package1 and another class called C in package2. Class C extends class A.

A has an instance variable which is declared like this:

protected int protectedInt = 1;

Here is the code for class A

package package1;

public class A {
    
    public int publicInt = 1;
    private int privateInt = 1;
    int defaultInt = 1;
    protected int protectedInt = 1;

}

And here is the code for class C:

package package2;
import package1.A;

public class C extends A{

    public void go(){
        //remember the import statement
        A a = new A();
        System.out.println(a.publicInt);
        System.out.println(a.protectedInt);
        
    }
}

Eclipse underlines the last line in C.go() and says "A.protectedInt" is not visible. It seems that this conflicts with the definition of the "protected" keyword, given the Oracle documentation says:

The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.

What's going on here?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
mahela007
  • 1,399
  • 4
  • 19
  • 29

6 Answers6

46

What's going on here?

You've misunderstood the meaning of protected. You can access the protected members declared in A from within C, but only for instances of C or subclasses of C. See section 6.6.2 of the JLS for details of protected access. In particular:

Let C be the class in which a protected member 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 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.)

So this code would be fine:

C c = new C();
System.out.println(c.publicInt);
System.out.println(c.protectedInt);
Community
  • 1
  • 1
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • In that case, why would java have a protected modifier at all? Wouldn't simply making C extend A be enough to make protectedInt visible to C? – mahela007 Sep 02 '13 at 13:31
  • 2
    @mahela007: Not without it being `protected`, no - if it were either default (package) visibility or `private`, it wouldn't be visible. – Jon Skeet Sep 02 '13 at 13:34
  • Hmm... The emphasized part in your answer says "access is permitted if E is a subclass if S".. But in my example, C is a subclass of A..and I still can't access the protected variable. – mahela007 Sep 02 '13 at 16:24
  • 2
    @mahela007: But `E` is `A` here, and `S` is `C`. Although `C` is a subclass of `A`, `A` *isn't* a subclass of `C`. – Jon Skeet Sep 02 '13 at 16:49
  • Ooh.. I think I get it now. Thank you very much for your help. This is a very non-intuitive concept (at least for me). Can you take a look at my comment on sanbhats answer? There's another part of the JLS that I don't understand.. – mahela007 Sep 02 '13 at 18:06
  • 1
    Please also have in mind that **protected methods and variables are visible not only to child classes BUT ALSO to classes within the same package** (just like the default objects are). So documentation is wrong saying *"if and only if"*. (Try this yourself everyone). – Alex Semeniuk Jun 09 '15 at 06:51
  • To simplify, In OP's code `a.protectedInt`, `protectedInt` is accessed using composition relation, so **NO** to visibility/access. In Jon skeet's example code `c.protectedInt`, `protectedInt` is accessed using inheritance relation, so **YES** to visibility/access. – overexchange Aug 06 '15 at 08:51
10

Since C is inheriting A, C can directly use the protected variable of A like below

public class C extends A{

    public void go(){

       System.out.println(protectedInt);

    }
}

As per your code, you are creating an instance of A and accessing protected variable through that instance, which violates java's rule - A protected variable is not visible outside the package

sanbhat
  • 17,522
  • 6
  • 48
  • 64
  • 1
    The original code will work if both classes are in the same package. – blgt Sep 02 '13 at 12:40
  • I read this from the JLC doc that Jon skeet posted. "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." How can the code that "implements an object" be outside the package of the same object? – mahela007 Sep 02 '13 at 16:14
  • @mahela007: Look at your example - the members are *declared* in `A`, which is in a different package to the class `C`, which is what "implements" an object of type `C`. – Jon Skeet Sep 02 '13 at 18:11
5

Protected means:

a) This member will be accessible to all classes in the same package through A object’s reference.

b) For different packages, this will be accessible only inside subclasses of A, say B, and the reference used can be a B instance or of any subclass of B.

Let's take an example:

Let A be a parent class in some package, say com.ex1.

Let B and C be classes in different packages w.r.t to A, say com.ex2. Also, B extends A and C extends B.

We will see how we can use protected fields of A inside B (a subclass of A).

A's code:

public class A {
    protected int a = 10;
}

B's code:

public class B extends A {


    public void printUsingInheritance() {
        // Using this
        System.out.println(this.a);
    }

    public void printUsingInstantiation() {
        // Using instance of B
        B b = new B();
        System.out.println(b.a);

        // Using instance of C as C is a subclass of B
        C c = new C();
        System.out.println(c.a);

        A a = new A();
        System.out.println(a.a); // Compilation error as A is not a subclass of B
    }
}

C's code:

public class C extends B {

}

For protected static:

Same rules apply except that in b) now it is accessible in any subclass of A by A's class reference. Reference

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Number945
  • 4,631
  • 8
  • 45
  • 83
3
 public void go(){
        //remember the import statement
        A a = new A();
        System.out.println(a.publicInt);
        System.out.println(a.protectedInt);

    }

When you are doing A a = new A(); and a.protectedInt you trying to access protected member of A which is illegal according to java standards

Instead you can do this.protectedInt directly.

Abhishek Singh
  • 10,243
  • 22
  • 74
  • 108
1

No need to instantiate Protection class inside Protection2 Class. You can directly call the protected variable without instantiating the Protection class. Because Protection2 class extends Protection class. So variable automatically inherited by subclass.

Try with below code:

public class Protection2 extends Protection{
Protection2()
{System.out.println("n_pro = " +n_pro);
}}
Sugumar
  • 11
  • 2
1

Within the same package where the protected member is declared, access is permitted:

package package1;

public class C extends A{
    public void go(){
        A a = new A();
        System.out.println(a.protectedInt);  // got printed 
        C c = new C();
        System.out.println(c.protectedInt);  // got printed as well
    }
}

Outside the package where the protected member is declared, access is permitted if and only if by code that is responsible for the implementation of that object. In this case, C is responsible for the implementation of that object, so it could access the protected.

package package2;

public class C extends A{
    public void go(){
        A a = new A();
        System.out.println(a.protectedInt);  // compiler complains  
        C c = new C();
        System.out.println(c.protectedInt);  // got printed
    }
} 
Ethan
  • 101
  • 1
  • 9