10

Code

I have the following class with a member interface:

package com.example.withinterface;

public class SomeClass {

    interface SomeInterface {

        void doSomething();
    }
}

And another class trying to access it:

package com.example.withinterface.main;

import com.example.withinterface.SomeClass;

public class Main {

    public static void main(String[] argss) {
        System.out.println(SomeClass.SomeInterface.class);
    }
}

Error

In Main I get the following error from javac: SomeInterface is not public in SomeClass; cannot be accessed from outside package.

And in Eclipse: SomeInterface is not public in SomeClass; cannot be accessed from outside package.

Both compiling as Java 7. Everything compiles fine if I make SomeInterface public.

But Spec says

The Java Language Specification for Java 7 says this:

A member interface is an interface whose declaration is directly enclosed in another class or interface declaration.

A member interface in a class declaration is implicitly public (§6.6) unless an access modifier is specified.

The Java Language Specification for Java 5 doesn't seem to have the second sentence.

Question

So shouldn't SomeInterface be considered public and shouldn't Main compile?

Update

As suggested by Ajay George this was indeed an error in the Java Language Specification 7 (thanks JamesB). In the meantime the spec was corrected and the incorrect sentence removed. Last version in Archive.org with the incorrect sentence.

Community
  • 1
  • 1
Arend v. Reinersdorff
  • 4,110
  • 2
  • 36
  • 40
  • Huh. I always assumed everything was package protected unless otherwise stated. I guess I learned something new. – Dennis Meng Jul 24 '12 at 20:17
  • 1
    I think this is because memeber that don't have an access modifier are having package-access. So they cannot be used by other packages –  Jul 24 '12 at 20:19
  • @Desolator Did you read the question? Member interfaces are **public by default**. – Marko Topolnik Jul 24 '12 at 20:22
  • My question is, what on Earth made them introduce this change?? Now there's no more package-level member interfaces. – Marko Topolnik Jul 24 '12 at 20:23
  • @MarkoTopolnik You mean we can't do something like `protected interface Foo`? Or am I wrong in assuming that would do the desired thing? – Dennis Meng Jul 24 '12 at 20:37
  • @DennisMeng Well, `protected` is not the same as package-private. There is no keyword to specify it. – Marko Topolnik Jul 24 '12 at 21:11
  • \*shrug\* Noted. Having the ability to have package-private things would be nice. – Dennis Meng Jul 24 '12 at 21:16
  • @DennisMeng Try this code out using Java 7 JDK and you will see that the JLS must be wrong as the code only compiles if the member interface is declared public. Hence, package-level member interfaces remain. – JamesB Jul 24 '12 at 21:43
  • I'll take your word for it for now; I'm still using Java 6 at the moment. – Dennis Meng Jul 24 '12 at 21:47

1 Answers1

2

I guess the spec is wrong . Here is the javap output with your code.

E:\workspace>javap com\example\withinterface\SomeClass
Warning: Binary file com\example\withinterface\SomeClass contains com.example.wi
thinterface.SomeClass
Compiled from "SomeClass.java"
public class com.example.withinterface.SomeClass {
  public com.example.withinterface.SomeClass();
}

E:\workspace>javap com\example\withinterface\SomeClass$SomeInterface
Warning: Binary file com\example\withinterface\SomeClass$SomeInterface contains
com.example.withinterface.SomeClass$SomeInterface
Compiled from "SomeClass.java"
interface com.example.withinterface.SomeClass$SomeInterface {
  public abstract void doSomething();
}

I changed the interface to public and then recompiled it.

E:\workspace>javap com\example\withinterface\SomeClass
Warning: Binary file com\example\withinterface\SomeClass contains com.example.wi
thinterface.SomeClass
Compiled from "SomeClass.java"
public class com.example.withinterface.SomeClass {
  public com.example.withinterface.SomeClass();
}

E:\workspace>javap com\example\withinterface\SomeClass$SomeInterface
Warning: Binary file com\example\withinterface\SomeClass$SomeInterface contains
com.example.withinterface.SomeClass$SomeInterface
Compiled from "SomeClass.java"
public interface com.example.withinterface.SomeClass$SomeInterface {
  public abstract void doSomething();
}

Note the difference in the Inner class.

Ajay George
  • 11,759
  • 1
  • 40
  • 48
  • 2
    I agree. The JLS is obviously wrong. Using Java 7 JDK, the code only compiles if the member interface is **explicitly** declared public. – JamesB Jul 24 '12 at 21:37
  • @JamesB No, the spec **cannot** by definition be wrong. What is wrong is the implementation. JLS is not descriptive, but **prescriptive**. – Marko Topolnik Jul 25 '12 at 07:54
  • @MarkoTopolnik it does look like a typo: *" A member interface in **a class** declaration is implicitly public"* should probably be *" A member interface in **an interface** declaration is implicitly public"*. It would make sense in the context of the previous sentence: *" enclosed in another class or interface declaration"*. – assylias Jul 25 '12 at 08:14
  • 1
    @assylias Well noted. Although it still doesn't make JLS wrong---it makes all implementations wrong :) I do hope they will rectify this. Where do isssues like this get posted? Maybe it has already been raised. – Marko Topolnik Jul 25 '12 at 08:19
  • 1
    BTW [it would not be the first time](http://stackoverflow.com/questions/2661210/errata-for-java-language-specification-3rd-edition). – assylias Jul 25 '12 at 08:20
  • @assylias Heh heh, already reading it :) There's the link to JSR 901, but still not helpful... – Marko Topolnik Jul 25 '12 at 08:24
  • 1
    @MarkoTopolnik I have raised this issue with Oracle by email. I used the info here: http://docs.oracle.com/javase/feedback.html – JamesB Jul 25 '12 at 10:51
  • @JamesB Would love to know their response on this. – Ajay George Jul 25 '12 at 13:47
  • OK, some typo in the JLS then. Great idea to use javap for this :-) – Arend v. Reinersdorff Jul 25 '12 at 18:49
  • 1
    @assylias Yes, probably a mistake or typo. But member types of interfaces are already discussed in the [JLS section 9.5](http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.5) – Arend v. Reinersdorff Jul 25 '12 at 18:52
  • @AjayGeorge Alex Buckley at Oracle has replied and a bug has been logged. When it is publicly available, I will post a link here. – JamesB Jul 25 '12 at 21:31