public class Test
{
static int i = 1;
static void m1()
{
}
}
class Test1 extends Test
{
int i = 1; //allowed
void m1() // not allowed; Both are instance level, so why this difference? Both can be accessed with super keyword
{
}
}
为什么不能使用相同的签名隐藏静态方法,但允许静态字段执行此操作?两者都是实例级别,那么为什么只允许静态字段?
答案 0 :(得分:8)
m1()
中的 Test
是static
方法,而m1()
中的Test1
是非静态方法。现在想象一下,如果允许这样做,那么当您执行以下语句时,运行时将选择哪个实现:
new Test1().m1();
由于子类的实例(在您的情况下为Test1
)可以访问,也可以从父类(来自Test
)访问静态方法。这就是不允许的原因。
下一个问题为什么Test1
中允许具有相同名称的变量:无法从子类实例访问父类'静态变量。换句话说,父类的静态状态是从子级隐藏的。那是
Test1.i; // compilation error, can't access parent's static variable
将导致编译错误。如果你试试
new Test1().i; // will access Test1's i variable
它将指向子类'状态而不是父类。这就是为什么子类可以具有相同名称的变量。
注意:如果i
中的Test
是非静态的,即使在这种情况下,Test1也可以包含名为i
的变量。在这种情况下,i
中的Test1
会在i
中隐藏Test
。
修改强>
来自Shahaan Syed的comment:
new Test1().i;
为什么这是我所关心的
用另一个词来表达Shahaan Syed的困惑:为什么
作为Kevin Esche commented,我还认为Java通过允许从子类实例访问父类的static
方法而搞砸了。虽然这不是一个好习惯,编译器也会生成警告。
以下是(JLS §8.3)的引用:
在这方面,隐藏字段不同于隐藏方法 (§8.4.8.3),因为静态和静态之间没有区别 字段隐藏中的非静态字段,而绘制了区别 方法隐藏中的静态和非静态方法之间。
但我在JLS中找不到任何理由。
我认为不应该生成警告而应该有编译时错误。那就是从子类实例访问父类的static
字段和static
方法,应该是编译器错误。在这方面,事情将是一致的,易于理解。但这又是我的想法。
同一行上另一个有趣的问题:Why isn't calling a static method by way of an instance an error for the Java compiler?