Home > front end >  Which part of the JLS talks about accessibility of members of local classes?
Which part of the JLS talks about accessibility of members of local classes?

Time:05-19

The java syntax allows member fields/methods of local classes to have access modifiers. But they have no effect at all. This seems to apply to anonymous classes as well.

This feels very counterintuitive. Is this behavior specified in the JLS?

Code:

class Foo {
  public static void main(String[] args) {
    class Bar {
      private int a = 1;
      protected int b = 2;
      public  int c = 3;
    }
    var bar = new Bar();
    System.out.println(bar.a);    // works for private a
    System.out.println(bar.b);    // works for protected b
    System.out.println(bar.c);    // works for public c
  }
}

CodePudding user response:

Yes. Just in the section about access modifiers - there is no separate section about 'the meaning of access modifiers specifically in the context of local classes' for the same reason there is no section about 'the meaning of access modifiers specifically when there's a full moon out' - there's nothing that changes here.

JLS §6.6.1 covers everything you need to determine exactly what happens (and conclude that they, indeed, have no effect here). I've intentionally picked JLS8, because 9 muddies the waters somewhat due to module scope stuff.

A member (class, interface, field, or method) of a reference type, or a constructor of a class type, is accessible only if the type is accessible and the member or constructor is declared to permit access:

Emphasis mine: The type is not accessible for any and all code, except the code inside the very method you've declared your local class in. That trivially means that access modifiers are completely irrelevant here for all code outside of your method - they can't even access Bar, therefore the accessibility of field a is moot.

Thus, we can restrict determining what each access modifier would do solely to '... to the code that tries to access it, which must therefore live in this very method, because anywhere else its trivially inaccessible due to the type being inaccessible'. Then:

public

Trivially, the code in the method can access public things.

nothing (package private)

Trivially, code in the method is in the same package as the local class is, by definition - package statements can only exist at the compilation unit level and these things are neccessarily in the same unit. Thus, yes, code in the method can access package private things.

protected

... is a superset of package private, therefore, yes, code in the method can access protected things.

private

From the JLS 6.6.1:

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.

By definition the local class is not a top-level class; the job of 'walk upwards in the syntax tree until you hit a top-level class', when applied to a local class, leads to the same answer, guaranteed, as when you apply it to the other code in the method the local class is in. Thus, yes, you can access private things.

Thus...

for all 4 access levels, the answer is the exact same thing: Yeah, you can. Hence, access modifiers are irrelevant. This isn't called out in the JLS because that's the result of applying the rules.

Guesses about intent

I did not personally design java-the-language. So, these are merely guesses:

  • Explicitly making any specification about the nature of access modifiers in local classes means the JLS is longer than it needs to be - the above behaviour is sensible enough (what else would you want here? Let's say that you wanted private stuff to be inaccessible - why? That's not how private works anywhere else in java, why should local classes be the one exception?)
  • Disallowing them entirely could be worthwhile, saving some 'room' in the mental model and the compiler specs, perhaps. However, that's problematic - local classes can implement things and extend something - and that may require certain access level (you cannot override a method and reduce its access level). The spec would then also have to say that for local classes the 'cannot reduce access level' rule is waived, and then would complicate everything for no reason.

CodePudding user response:

The reason And example of why it is useful to be able to specify access modifiers is to allow local and anonymous classes to implement interfaces, which require the implementing methods to be public, or to allow local and anonymous classes to extend other classes and override public methods. (You cannot make the access specifier of a method more restrictive when you override it).

For example:

class Foo {
    public static void main(String[] args) {
        Comparator<String> byLength = new Comparator<String>() {
            // Need to make this method public because the method
            // in interface Comparator is public
            @Override
            public int compare(String o1, String o2) {
                return Integer.compare(o1.length(), o2.length());
            }
        };

        // ...
    }
}

For other use cases, the Java language designers probably simply didn't bother to add extra rules to explicitly forbid access modifiers. It would just have made the rules of the language more complicated, and the ability to specify access modifiers here isn't useful, but doesn't do any harm either.

  •  Tags:  
  • java
  • Related