我真的想知道为什么,而不是去看文档。假设我有这样的课:
public class OuterClass{
public static void main(String[] args)throws Exception{
System.out.println(OuterClass.InnerClass.yearOfBorn);//works ok
System.out.println(OuterClass.InnerClass.returnYearOfBorn());//not works
System.out.println(OuterClass.InnerClass.returnYearOfBornAsPublic());//not works
}
private final class InnerClass{
private static final int yearOfBorn=13;
private static int returnYearOfBorn(){
return yearOfBorn;
}
public static int returnYearOfBornAsPublic(){
return yearOfBorn;
}
}
}
两个静态方法都会抛出一个错误,说明
修饰符 'static' 只允许在常量变量声明中
我知道文档指出 Java 语言规范第 §8.1.3 节对此进行了描述
8.1.3 内部类和封闭实例
内部类是未显式或隐式声明为静态的嵌套类。内部类不得声明静态初始值设定项(第 8.7 节)或成员接口。内部类不能声明静态成员,除非它们是编译时常量字段(第 15.28 节)。
但是我的问题是调用简单值或属性与调用静态方法(无论是公共还是私有)之间有什么区别?为什么可以调用属性但不能调用方法?
非静态内部类有一些特殊之处。
静态内部类没有它。顶级课程没有它。任何内部接口或枚举都没有它。
那个特殊的东西是一个看不见的场。
这个不可见字段的类型是
Outer
,而且它是final
。它首先在其构造函数中进行初始化,是的,非静态内部类的每个构造函数都有一个神奇的不可见参数(类型为 Outer
)来充当此字段。
所以,当你写:
public class Outer {
public class Inner {
}
}
编译器将编译此代码,就像您实际编写的一样:
public class Outer {
public static class Inner {
private final Outer I_AM_MAGIC;
public Inner(Outer outer) {
this.I_AM_MAGIC = outer;
}
}
}
使用
javap
反编译工具就可以看到这个隐藏的魔法;传入 -verbose
和 -private
你就会看到这些。这种魔法存在的原因是您可以从内部调用外部的实例方法,但是..您在什么实例上调用这些外部方法?在那个隐藏的实例上!
请注意,这个奇异的、看似奇怪的代码:
someOuter.new Inner()
实际上是合法的java代码。当从 new Inner()
中的非静态上下文中调用 Outer
时,this
实例将作为不可见参数传递给该构造函数,但如果您不在那里,则代码根本无法编译...除非您使用 outer.new Inner()
语法。
编译器阻止您向
Inner
添加静态方法的原因是,它被认为会导致一些混乱。基本上,你的问题的答案是:“没有充分的理由......只是......规范说java编译器不允许它,因此,javac不允许它”。
请注意,实际上这些非静态内部类是令人困惑的。我强烈建议你自学永远让你的内心课程
static
除非你真的知道你在做什么。即便如此,也要三思而后行。然后再三思。然后也许可以考虑制作一个非静态内部类。