5

这是来自 JLS 部分 8.4.8.2 的简短示例。

class Super {
    static String greeting() { return "Goodnight"; }
    String name() { return "Richard"; }
}
class Sub extends Super {
    static String greeting() { return "Hello"; }
    String name() { return "Dick"; }
}
class Test {
    public static void main(String[] args) {
        Super s = new Sub();
        System.out.println(s.greeting() + ", " + s.name());
    }
}

根据示例的讨论,运行的输出main()将是“晚安,迪克”。这是因为静态方法是根据调用它们的变量/表达式的静态类型来调用的。

这是我的问题:任何对流敏感的编译器都可以计算出s调用时存储的任何对象的类型必须始终为Sub,因此如果允许编译器使用该信息,即使调用静态方法也可能有一些动态绑定的感觉。为什么不允许这样做?Java 是否有明确的目标,即每个编译器都生成行为完全相同的字节码,还是有其他原因?

4

2 回答 2

3

其实这里s.greeting()就相当于Super.greeting()因为s被定义为Super和静态方法不关心类实例。正如你肯定知道的那样,它们是全班的。所以直接从类实例调用静态方法是没有意义的。当然,实例sSub()您指定的,因此调用了非静态方法Sub.name()

来自Java 官方教程

您还可以使用对象引用来引用静态字段,例如

myBike.numberOfBicycles

但不鼓励这样做,因为它没有明确说明它们是类变量。

允许静态方法在类实例方面是明智的,只会使代码的可读性更低、更神秘、更难调试,而无需真正添加任何有用的特性。

于 2012-07-12T20:32:10.530 回答
1

它不是太特定于java。想象一下你的“智能”编译s.getClass().greeting()

class A extends Sub {
    static String greeting() { return "Allo"; }
}
class B extends Sub {
    static String greeting() { return "Brrr"; }
}
Super s = condition? new A() : new B();
assert s.greeting.equals(Sub.greeting()); // If compiler cannot infer condition.

编译器是否应该跨多个源执行此操作?库外,源代码可能不可用。

我宁愿认为java中的谬误是,这s.greeting()是允许的。

由于静态继承没有用,最好不要发明这样的功能。

于 2012-07-12T20:54:20.010 回答