Clarification about accessibility of private members

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Mon Oct 3 09:50:23 UTC 2016



On 30/09/16 22:31, Eddie Aftandilian wrote:
> JLS 6.6.1 says, "Otherwise, the member or constructor is declared 
> private, and access is permitted if and only if it occurs within the 
> body of the top level class (§7.6) that encloses the declaration of 
> the member or constructor."  Under that definition, I believe the 
> following code should be legal:
>
> class Holder {
>   class Super {
>     private String s1;
>   }
>   class Sub extends Super {
>     private String doIt() {
>       return s1;
>     }
>   }
> }
>
> Holder is the top level class that encloses the declaration of s1, and 
> the "return s1" statement occurs inside Holder's body.  However, javac 
> 1.8.0 issues an error on this code:
>
> Holder.java:7: error: s1 has private access in Holder.Super
>       return s1;
>              ^
> 1 error
>
> What am I missing?
I think there's another aspect at stake here: interplay between 
inheritance and scoping. But let's start from the beginning: the rules 
for checking that 's1' is a valid field identifier are defined in 6.5.6.1:

"If an expression name consists of a single Identifier, then there must 
be exactly one declaration denoting either a local variable, parameter, 
or field *visible* (§6.4.1) at the point at which the Identifier occurs. 
Otherwise, a compile-time error occurs."

What does 'visible' mean? Let's expand 6.4.1:

"A declaration d is said to be visible at point p in a program if the 
scope of d includes p, and d is not shadowed by any other declaration at p."

Ok, so the question we need to ask is: does the scope of 's1' includes 
the instance method doIt() ?

The scope of a field is defined as follows in JLS 6.3:

"The scope of a declaration of a member |m| declared in or inherited by 
a class type C (§8.1.6 
<https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.6>) 
is the entire body of C, including any nested type declarations."

So, from the perspective of 'Sub' the only way for it to have a field 
's1' in scope is:

* if it declares the field 's1'
* if it inherits a field 's1'

In your example, the first bullet clearly does not apply: 'Sub' doesn't 
declare any fields. So the question is, does 'Sub' inherits 's1' from 
'Super' ? The answer is again no, this time because of JLS 8.2. (Class 
Members):

"Members of a class that are declared |private| are not inherited by 
subclasses of that class."

That is, 's1' is not inherited because it is declared private in 'Sup'. 
Popping back, this means that 's1' is not visible inside 'doIt()' and 
therefore the error message you get is expected.

Maurizio
> Thanks,
> Eddie

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20161003/734ceb34/attachment.html>


More information about the compiler-dev mailing list