0

Today, I reviewed same Android code, and found a strange phenomenon.

It is the anonymous internal class directly called the external class instance method.

In my mind, directly calling a method is equivalent to adding this directly before the method, and this is an instance of an inner class.

According to this logic, an instance of an external class is invoked directly in the anonymous inner class, that will caused the compile ERROR.

But actually compile this application, and no problem. And the running log is normal.

Therefore, writing a simple Demo to verify the previous concept is wrong. code show as below:

public class InnerClass {
    public static void main(String[] args) {
        new InnerClass().process();
    }

    public void process() {
        new Thread() {
            @Override
            public void run() {
                System.out.println(toString("test"));
            }
        }.start();
    }

    public String toString(String string) {
        return string;
    }
}

In the Oracle:
enter image description here

In the OpenJDK:
enter image description here

So, What is the difference of the anonymous internal class directly call the external class instance method in the OpenJDK and Oracle?

Where can I find documentation to see these differences?

I worked hard, but did not get a clear answer.

Thanks.

P.S.

In According to my point of view

public class InnerClass {
    public static void main(String[] args) {
        new InnerClass().process();
    }

    public void process() {
        new Thread() {
            @Override
            public void run() {
                // In According to my point of view
                // toString("test")
                // <==>
                // this.toString("test")
                // and `this` is the instance of Thread
                // what's the error of my view?
                System.out.println(toString("test"));
            }
        }.start();
    }

    public String toString(String string) {
        return string;
    }
}

image

fxleyu
  • 119
  • 8
  • https://stackoverflow.com/questions/17360011/technically-what-is-the-main-difference-between-oracle-jdk-and-open-jdk –  Dec 09 '17 at 03:44
  • 2
    Also note that one is Java 8, the other java 7. – Thorbjørn Ravn Andersen Dec 09 '17 at 03:54
  • @MacStevins I see the url., But I cannot find the detail. For example the difference of that javac handle anonymous inner class directly call an instance method of an outer class – fxleyu Dec 09 '17 at 03:56
  • Why are you comparing Windows and Unix? And Java 7 to Java 8? Limit the external differences before you say there is a difference in the software itself. – OneCricketeer Dec 09 '17 at 04:05
  • There is no such difference between OpenJDK and Oracle javac (and there won’t be any in the future). You are just comparing Java 7 to Java 8 (on different OS and locales). – eckes Dec 09 '17 at 04:10

1 Answers1

1

The problem is that

        public void run() {
            System.out.println(toString("test"));
        }

is calling toString on the anonymous Thread subclass, and that is Thread::toString(). There is no Thread::toString(String), and the toString(String) method from the enclosing scope is not considered.

The JLS states that it will only check an enclosing / outer class for a method if there is no method with the required name in the inner class. See JLS 15.12.1:

If the form is MethodName, that is, just an Identifier, then:

  • If the Identifier appears in the scope of a visible method declaration with that name (§6.3, §6.4.1), then:

    • If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T.

      This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy. See §6.5.7.1 for an example.

As to why OpenJDK Java 7 accepts your test class .... if that is actually true, I'd call that a compiler bug. But it would be a general Java 7 bug not an OpenJDK specific one. The javac codebases are (AFAIK) identical for Oracle and OpenJDK releases of the same version.

Interestingly, I have a copy of Oracle Java 6, and javac from that version also calls this a compilation error as well.

$ /usr/java/jdk1.6.0_45/bin/javac InnerClass.java 
InnerClass.java:10: cannot find symbol
symbol: method toString(java.lang.String)
                System.out.println(toString("test"));
                                   ^
1 error

So ... maybe ... you should rerun your OpenJDK Java 7 test, and make sure you are compiling the same source code!

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • `toString(String)` is not `toString()`. And it is in both cases `Thread#toString` – eckes Dec 09 '17 at 04:12
  • I know that ......... – Stephen C Dec 09 '17 at 04:13
  • hm, why do you say it calls Object.toString() then? – eckes Dec 09 '17 at 04:16
  • Because it is **just** the name that matters in this case. See the JLS text I have just quoted. Indeed, read the whole context. – Stephen C Dec 09 '17 at 04:21
  • Rule #1 - If the java compiler says some code is incorrect, then *believe* the java compiler ... unless the JLS clearly contradicts it. In this case, there are 3 versions of javac saying this is incorrect. (I have also tested OpenJDK Java 8.) – Stephen C Dec 09 '17 at 04:22
  • Well, yes the code is clearly incorrect, it’s interesting to know why it compiles ,) – eckes Dec 09 '17 at 04:24
  • Well, I'm not convinced that it does. But I can't easily get hold of the OpenJDK compiler that the OP is using ... to check for myself. – Stephen C Dec 09 '17 at 04:25
  • BTW i would change `Runnable` into anonymous `Thread` subtype, or do you think it’s related to the run() declaration? — I think in that case it’s more the lexical scope, right? – eckes Dec 09 '17 at 04:28
  • I see `new Thread() { }` in the original question. So talking about Runnable seems confusing. – eckes Dec 09 '17 at 04:31
  • 1
    Ah .... I see what you mean. – Stephen C Dec 09 '17 at 04:32
  • BTW (The more often I read that JLS part the less I understand what it means :) – eckes Dec 09 '17 at 04:35
  • Rule #2 - if you don't understand what the JLS means, it *probably* means what the java compiler says it means :-) – Stephen C Dec 09 '17 at 04:37
  • 6.5.7.1 does describe it a bit simpler to understand, (still surprising never encountered that before). It is a bit unexpected when you are not familiar with method names as identifiers. Wonder if that really helps in cases. – eckes Dec 09 '17 at 04:48
  • I can make sure you are compiling the same source code! – fxleyu Dec 09 '17 at 05:03
  • I can assure you that >>I<< am compiling the same source code with OpenJDK Java 6 and Java 8. Anyhow, it is not really relevant. If you are getting a compiler to accept that code, then that compiler has a bug in it. Fix your code, move on. – Stephen C Dec 09 '17 at 06:46