简短的回答:大多数程序员对作用域如何工作的心智模型不是 javac 使用的模型。匹配更直观的模型需要对 javac 的工作方式进行重大更改。
内部类中的静态成员是可取的主要原因是为了代码清洁 - 仅由内部类使用的静态成员应该存在于其中,而不是必须放置在外部类中。考虑:
class Outer {
int outID;
class Inner {
static int nextID;
int id = nextID++;
String getID() {
return outID + ":" + id;
}
}
}
考虑一下当我使用非限定标识符“outID”时 getID() 中发生了什么。此标识符出现的范围类似于:
Outer -> Inner -> getID()
在这里,再次因为这正是 javac 的工作方式,范围的“外部”级别包括 Outer 的静态成员和实例成员。这很令人困惑,因为我们通常被告知将类的静态部分视为范围的另一个级别:
Outer static -> Outer instance -> instanceMethod()
\----> staticMethod()
这样想,staticMethod()当然只能看到Outer的静态成员。但是,如果 javac 是这样工作的,那么在静态方法中引用实例变量将导致“名称无法解析”错误。真正发生的是名称是在范围内找到的,但随后会进行额外级别的检查,并确定该名称是在实例上下文中声明的,并且是从静态上下文中引用的。
好的,这与内部类有什么关系?天真地,我们认为内部类没有理由不能拥有静态作用域,因为我们正在想象作用域是这样工作的:
Outer static -> Outer instance -> Inner instance -> getID()
\------ Inner static ------^
换句话说,内部类中的静态声明和外部类中的实例声明都在内部类的实例上下文的范围内,但它们实际上都没有嵌套在另一个中;两者都嵌套在 Outer 的静态范围内。
这不是 javac 的工作方式——静态成员和实例成员都有一个单一级别的范围,并且范围总是严格嵌套。甚至继承也是通过将声明复制到子类而不是分支和搜索超类范围来实现的。
为了支持内部类的静态成员,javac 必须拆分静态和实例范围并支持分支和重新加入范围层次结构,或者它必须扩展其简单的布尔“静态上下文”思想以更改以跟踪所有级别的上下文类型当前范围内的嵌套类。