方法隐藏和字段隐藏的继承帮助

Sha*_*yed 8 java inheritance

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
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么静态方法不能用相同的签名隐藏,但允许静态字段执行此操作?两者都是实例级别,那么为什么只允许静态字段?

sud*_*d29 8

m1()在类中Test是一个static方法,而m1()in Test1是非静态的.现在想象一下,如果允许这样做,那么当你执行下面的语句时,运行时会选择哪个实现:

new Test1().m1();
Run Code Online (Sandbox Code Playgroud)

由于子类的实例(Test1在您的情况下)可以访问也从父类(从Test)访问静态方法.这就是为什么不允许这样做的原因.

对于下一个问题,为什么允许具有相同名称的变量Test1:父类'静态变量无法从子类实例访问.换句话说,父类的静态状态是从子级隐藏的.那是

Test1.i;   // compilation error, can't access parent's static variable
Run Code Online (Sandbox Code Playgroud)

将导致编译错误.如果你试试

new Test1().i; // will access Test1's i variable
Run Code Online (Sandbox Code Playgroud)

它将指向子类的状态而不是父类.这就是为什么子类可以具有相同名称的变量.

注意:如果iin Test是非静态的,即使在这种情况下,Test1也可以包含名称变量i.在这种情况下,iTest1将阴影iTest.

编辑

来自Shahaan Syed的评论:

new Test1().i; 为什么允许这是我所关心的

将Shahaan Syed的混淆换成另一个词:为什么

  • 在变量的情况下,子类可以有一个非静态变量,而父类有一个具有相同名称的静态变量,
  • 另一方面,当父类具有相同名称的静态方法时,子类不能有非静态方法?

正如Kevin Esche 评论的那样,我也认为Java通过允许static从子类实例访问父类的方法而搞砸了.虽然这不是一个好习惯,编译器也会生成警告.

这是(JLS§8.3)的引用:

在这方面,隐藏字段不同于隐藏方法(第8.4.8.3节),因为在字段隐藏中静态和非静态字段之间没有区别,而在方法隐藏中区分静态和非静态方法.

但我在JLS中找不到任何理由.

我认为不应该产生警告而应该有编译时错误.即从子类实例访问父类的static字段和static方法,应该是编译器错误.在这方面,事情将是一致的,易于理解.但这又是我的想法.

同一行上另一个有趣的问题:为什么不通过实例调用静态方法是Java编译器的错误?

  • 为了补充这个答案,很有可能这样做是为了避免混淆,因为混淆本身就是一种糟糕的语言设计(能够在对象实例上调用静态方法). (4认同)
  • @ShahaanSyed因为在这一点上java语言的设计很差.可悲的是,这是唯一合理的答案. (2认同)