javaanonymous-classjls

Anonymous classes can refer to inaccessible type in the signature of the supertypes?


Consider the following clause from JLS 8: § 15.9.5.1. Anonymous Constructors

Note that it is possible for the signature of the anonymous constructor to refer to an inaccessible type (for example, if such a type occurred in the signature of the superclass constructor cs). This does not, in itself, cause any errors at either compile-time or run-time.

I tried to generate an example for this - and came up with the following:

.
└── com
    └── example
        ├── inaccessible
        │   └── InaccessibleType.java
        ├── subclass
        │   └── SubClass.java
        └── superclass
            └── SuperClass.java

And the code being the following:

-> InaccessibleType.java

package com.example.inaccessible;
public class InaccessibleType {
  public void display() {
    System.out.println("InaccessibleType instance");
  }
}

-> SuperClass.java

package com.example.superclass;

// Importing the superclass
import com.example.inaccessible.InaccessibleType;

public class SuperClass {
  public SuperClass(InaccessibleType it) {
    it.display();
  }
}

-> SubClass.java

package com.example.subclass;

import com.example.superclass.SuperClass;

public class SubClass {
  public static void main(String[] args) {
    // Creating an anonymous class that extends SuperClass
    SuperClass instance = new SuperClass(new InaccessibleType() {
      // This anonymous class does not have access to InaccessibleType
    }) {
      // Anonymous constructor referring to InaccessibleType
      // No errors here even though InaccessibleType is inaccessible
    };
  }
}

Now despite the above statement given in the JLS - I am still getting compilation error in the subclass

javac com/example/inaccessible/*.java com/example/subclass/*.java com/example/superclass/*.java                                                                                    ─╯
com/example/subclass/SubClass.java:8: error: cannot find symbol
    SuperClass instance = new SuperClass(new InaccessibleType() {
                                             ^
  symbol:   class InaccessibleType
  location: class SubClass
1 error

Now sure - if my understanding of the above clause correct? - and what can be the example that explains the above clause correctly?


Solution

  • "Inaccessible" in this case does not mean "cannot refer to it using its simple name". It means "inaccessible as per the rules of Access Control".

    According to the rules of Access Control, InaccessibleType is totally accessible in Subclass because it is public. You just need to say com.example.inaccessible.InaccessibleType, or InaccessibleType if you import it.

    One example of the situation that the JLS is talking about is,

    public class Superclass {
        private static class Nested {}
    
        public Superclass(Nested n) {}
    }
    

    Superclass.Nested is inaccessible outside of Superclass. In some other class, I can create an anonymous class inheriting Superclass:

    new Superclass(null) { };
    

    This anonymous class will have a constructor that takes a parameter of type Superclass.Nested. The JLS says that this is OK. This code compiles and runs as expected.

    In contrast, you cannot create a non-anonymous subclass of Superclass that has a constructor with the same signature:

    class Subclass extends Superclass {
    
        public Subclass(Superclass.Nested n) { // This will produce an error
            super(n);
        }
    }