Java中静态方法不支持动态多态的原因

3

为什么Java不支持静态方法的动态多态性? 如果答案是“静态方法不应该在实例上调用,因此方法调用不需要在运行时解析”,那么更进一步的问题是:‘为什么Java允许我在实例上调用静态方法?’ 为什么Java不通过给出一些编译时错误来阻止用户直接在实例上调用该方法。

反过来说,如果Java支持静态方法的运行时多态性会有什么问题?


这根本没有意义。由于类在编译时确定,因此不存在多态的可能性。在实例上调用静态方法有点(在我看来)愚蠢的编译器手法。你真正做的是在引用变量的声明类上调用静态方法——这在编译时确定。 - Hot Licks
1
我同意你所说的,但我的疑问是为什么不阻止用户不需要使用的功能呢? - Tushar Baviskar
1
Smalltalk确实支持这一点,因此完全可以实现。我认为这只是Java所做的设计决策之一,说实话我从来没有想念过它。 - Seb
那么进一步的问题是,“为什么Java允许我在实例上调用静态方法?”这是一个错误,但现在无法更改,因为它会产生破坏性变化。 - Powerlord
4个回答

7
为什么Java允许我在实例上调用静态方法?
你的假设是错误的。它从来不会在类的实例上调用,而总是在类上调用。
尝试以下示例代码,你将永远不会得到NullPointerException。
class ABC {
    public static void hello() {
        System.out.println("Hello");
    }
}

ABC abc = null;
abc.hello(); 

如果Java支持静态方法的运行时多态性,会发生什么问题? 当你在子类中重写方法时,多态性就会出现。由于静态方法属于类,因此没有重写静态方法的意义。因此,多态性总是仅对属于类实例的实例方法有效。请参考重写

我假设你已经实例化了该类,才能调用静态方法。 - Tushar Baviskar
1
我没有该类的任何实际对象。它是一个“null”引用。 - Braj
2
虽然这一切都是真实的,但构建一个自洽继承模型以适用于静态方法是可能的(并且在某些情况下可能会有用 - 例如每个扩展 Tile 的类都有一个静态的 initialiseGraphicsForClass 方法,而您将类传递给方法)。因此,问题仍然存在;为什么不呢? - Richard Tingle

1
静态方法是基于变量的类型而不是实例的类来解析的。这允许进行一些优化,因为在编译时总是知道要调用的确切方法。允许多态静态方法将防止这种情况发生。
允许在实例上调用静态方法的结果如下。
class A {
    static void func() {}
}

class B extends A {
    static void func() {}
}

B b = new B();
A a = b;

b.func(); // calls B.func()
a.func(); // same instance, but calls A.func()

非常混乱和不直观。基于静态方法的实现,允许在实例上调用静态方法是一个重大的设计缺陷,应该始终避免。
根据定义,静态方法不需要实例来调用。通过允许多态调用,你需要一个实例,如果你需要一个实例来确定调用哪个方法,那么为什么这个方法是静态的呢?

2
我真的不赞成为静态方法支持动态多态性,但如果Java支持在实例上调用静态方法,则应完全支持它(就像实例方法一样),或者完全阻止用户在实例上调用静态方法。 - Tushar Baviskar

0

动态多态性可以支持方法重写。但是对于静态方法重写来说是不可能的,因为它会导致方法隐藏。因此,动态多态性不支持静态方法。


-1
我很高兴可以通过类的实例调用静态方法。这使我能够从实例中调用方法而无需资格限定符。如果我尝试(合法但不合理地)通过实例调用它,我的IDE会警告我。
public static void foo() {
    //yadda yadda
}

public void bar() {
    foo(); // this is legal
    MyClass.foo() // this is also legal, but would be necessary if I couldn't call it through the instance
}

// in some other class:
new MyClass().foo() // this is legal but silly and my IDE warns me about it

1
但是如果一个超类声明了一个名为foo的实例方法会发生什么?应该调用哪个方法:实例方法还是静态方法?我相信实例方法优先于静态方法被调用。这意味着另一个人可能会更改超类而没有意识到他们正在影响子类。 - Dunes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接