我一直在努力理解java编译,我遇到了一个问题。假设我们有一个类似这样的课程
public class Ambiguity
{
static class G
{
void A()
{
System.out.println("Regular Method");
}
}
static class b
{
static void A()
{
System.out.println("Static Method");
}
}
public static void main(String[] args)
{
G b = new G();
b.A();
}
}
编译器如何知道天气来调用static void A()
中的方法class b
或void A()
类型的对象b
上的常规方法G
。根据我运行的测试,它似乎调用对象b
(类型G
)方法,但我不知道这是否始终是标准过程。在这种情况下,如何调用静态方法。
答案 0 :(得分:6)
b
,类型为G
,b
的名称,其中变量b
为in scope。 b
上的方法。模糊发生,因为本地范围的变量更具体。模糊的规则很复杂,但在JLS §6.4.2:
中进行了总结在上下文中可能会出现一个简单的名称,可能会将其解释为变量,类型或包的名称。在这些情况下,§6.5的规则指定变量将优先于类型,并且将优先选择类型与包。因此,有时可能无法通过其简单名称引用可见类型或包声明。我们说这样的声明是模糊的。
这样的模糊是不好的做法,应该避免。但是,通过为类型提供限定名称(§6.2),您可以解决这种情况的歧义。这会更改§6.5的适用名称选择规则:
G b = new G();
Ambiguity.b.A(); // calls Ambiguity.b.A()
b.A(); // calls Ambiguity.G.A() on variable b
打印:
Static Method Regular Method
~~~~
具体而言,此上下文中的非限定名称b
最初被分类为不明确名称(§6.5.1)。然后由§6.5.2的优先级规则重新分类(粗体是我的突出显示,斜体是我的补充):
如果AmbiguousName是一个简单的名称,由一个标识符
组成•如果标识符在局部变量声明(第14.4节)或参数声明(第8.4.1节,§8.8.1,§14.20)的范围(§6.3)内出现 )或具有该名称的字段声明(第8.3节),然后AmbiguousName被重新分类为ExpressionName ( ...而不是TypeName,来自较低优先级规则3 )。
答案 1 :(得分:1)
将调用“最佳匹配”。对象比静态方法更精确,因此默认情况下将使用对象方法;你可以通过Class.Method();
调用静态方法。这里真正错误的是你的局部变量b恰好与类同名,因此它隐藏了类。
如果使用完整路径,您仍然可以调用类静态方法:Ambiguity.b.A();
答案 2 :(得分:0)
在这种情况下,为了解决歧义,你应该致电:
Ambiguity.b.A();
Java优先考虑范围较小的变量。在这种情况下,Ambiguity.b实际上不是一个变量,但具有全局范围,因为它不属于实例对象。