今天,我查看了相同的Android代码,发现了一个奇怪的现象。
它是直接称为外部类实例方法的匿名内部类。
在我看来,直接调用方法相当于在方法之前直接添加this
,this
是内部类的实例。
根据这个逻辑,在匿名内部类中直接调用外部类的实例,这将导致编译错误。
但实际上编译这个应用程序,没问题。运行日志正常。
因此,编写一个简单的Demo来验证以前的概念是错误的。代码如下所示:
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;
}
}
那么,匿名内部类有什么区别直接调用OpenJDK和Oracle中的外部类实例方法?
我在哪里可以找到文档来查看这些差异?
我努力工作,但没有得到明确的答案。
感谢。
P.S。
根据我的观点
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;
}
}
答案 0 :(得分:1)
问题在于
public void run() {
System.out.println(toString("test"));
}
在匿名toString
子类上调用Thread
,即Thread::toString()
。没有Thread::toString(String)
,并且不考虑封闭范围中的toString(String)
方法。
JLS声明如果在内部类中没有具有所需名称的方法,它将仅检查方法的封闭/外部类。见JLS 15.12.1:
如果表单是MethodName,即只是一个标识符,那么:
如果标识符出现在可见方法声明的范围内 使用该名称(§6.3,§6.4.1),然后:
如果存在该方法为成员的封闭类型声明,则让T为最内层的类型声明。班级或 搜索界面是T。
此搜索政策称为“梳理规则”。它在查找之前有效地在嵌套类的超类层次结构中查找方法 用于封闭类及其超类层次结构中的方法。看到 §6.5.7.1为例。
至于为什么OpenJDK Java 7接受你的测试类....如果确实如此,我称之为编译器错误。但它将是一个普通的Java 7错误,而不是OpenJDK特有的错误。对于同一版本的Oracle和OpenJDK版本,javac
代码库(AFAIK)完全相同。
有趣的是,我有一份Oracle Java 6,该版本的javac
也称此为编译错误。
$ /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
所以......也许......你应该重新运行你的OpenJDK Java 7测试,并确保你正在编译相同的源代码!