为什么不可能重写静态方法?

如果可能,请举例说明。


当前回答

Well... the answer is NO if you think from the perspective of how an overriden method should behave in Java. But, you don't get any compiler error if you try to override a static method. That means, if you try to override, Java doesn't stop you doing that; but you certainly don't get the same effect as you get for non-static methods. Overriding in Java simply means that the particular method would be called based on the run time type of the object and not on the compile time type of it (which is the case with overriden static methods). Okay... any guesses for the reason why do they behave strangely? Because they are class methods and hence access to them is always resolved during compile time only using the compile time type information. Accessing them using object references is just an extra liberty given by the designers of Java and we should certainly not think of stopping that practice only when they restrict it :-)

示例:让我们试着看看如果我们尝试重写一个静态方法会发生什么:-

class SuperClass {
// ......
public static void staticMethod() {
    System.out.println("SuperClass: inside staticMethod");
}
// ......
}

public class SubClass extends SuperClass {
// ......
// overriding the static method
public static void staticMethod() {
    System.out.println("SubClass: inside staticMethod");
}

// ......
public static void main(String[] args) {
    // ......
    SuperClass superClassWithSuperCons = new SuperClass();
    SuperClass superClassWithSubCons = new SubClass();
    SubClass subClassWithSubCons = new SubClass();

    superClassWithSuperCons.staticMethod();
    superClassWithSubCons.staticMethod();
    subClassWithSubCons.staticMethod();
    // ...
}
}

输出: SuperClass:在staticMethod内部 SuperClass:在staticMethod内部 子类:staticMethod内部

注意输出的第二行。如果staticMethod被重写,这一行应该与第三行相同,因为我们在运行时类型的对象上调用'staticMethod()'作为'子类'而不是'超类'。这证实了静态方法总是只使用它们的编译时类型信息进行解析。

其他回答

一般来说,允许“重写”静态方法是没有意义的,因为没有好的方法来确定在运行时调用哪个方法。以Employee为例,如果我们调用regularemploee . getbonusmultiplier()——应该执行哪个方法?

以Java为例,人们可以想象这样一种语言定义:只要静态方法是通过对象实例调用的,就可以“覆盖”它们。然而,这样做只是重新实现常规的类方法,在没有真正带来任何好处的情况下为语言增加冗余。

Here is a simple explanation. A static method is associated with a class while an instance method is associated with a particular object. Overrides allow calling the different implementation of the overridden methods associated with the particular object. So it is counter-intuitive to override static method which is not even associated with objects but the class itself in the first place. So static methods cannot be overridden based on what object is calling it, it will always be associated with the class where it was created.

通过重写,我们可以根据对象类型创建一个多态性质。静态方法与对象无关。因此java不支持静态方法重写。

其实我们错了。 尽管Java默认情况下不允许重写静态方法,但如果你彻底查看Java中Class和Method类的文档,你仍然可以通过以下工作方法来模拟静态方法重写:

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;

class RegularEmployee {

    private BigDecimal salary = BigDecimal.ONE;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".02");
    }
    public BigDecimal calculateBonus() {
        return salary.multiply(this.getBonusMultiplier());
    }
    public BigDecimal calculateOverridenBonus() {
        try {
            // System.out.println(this.getClass().getDeclaredMethod(
            // "getBonusMultiplier").toString());
            try {
                return salary.multiply((BigDecimal) this.getClass()
                    .getDeclaredMethod("getBonusMultiplier").invoke(this));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }
    // ... presumably lots of other code ...
}

final class SpecialEmployee extends RegularEmployee {

    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

public class StaticTestCoolMain {

    static public void main(String[] args) {
        RegularEmployee Alan = new RegularEmployee();
        System.out.println(Alan.calculateBonus());
        System.out.println(Alan.calculateOverridenBonus());
        SpecialEmployee Bob = new SpecialEmployee();
        System.out.println(Bob.calculateBonus());
        System.out.println(Bob.calculateOverridenBonus());
    }
}

输出结果:

0.02
0.02
0.02
0.03

我们想要达到的目标:)

即使我们将第三个变量Carl声明为regulareemployee并给它分配了SpecialEmployee实例,我们仍然会在第一种情况下调用regulareemployee方法,在第二种情况下调用SpecialEmployee方法

RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());

看看输出控制台:

0.02
0.03

;)

静态方法被JVM视为全局方法,根本不绑定到对象实例。

如果可以从类对象中调用静态方法(就像在Smalltalk等语言中那样),那么在概念上是可能的,但在Java中却不是这样。

EDIT

你可以重载静态方法,没关系。但是你不能重写静态方法,因为类不是一级对象。您可以使用反射在运行时获取对象的类,但所获得的对象并不与类层次结构并行。

class MyClass { ... }
class MySubClass extends MyClass { ... }

MyClass obj1 = new MyClass();
MySubClass obj2 = new MySubClass();

ob2 instanceof MyClass --> true

Class clazz1 = obj1.getClass();
Class clazz2 = obj2.getClass();

clazz2 instanceof clazz1 --> false

你可以对类进行反射,但它仅限于此。使用clazz1.staticMethod()不会调用静态方法,而是使用MyClass.staticMethod()。静态方法不绑定到对象,因此在静态方法中没有this或super的概念。静态方法是一个全局函数;因此,也没有多态性的概念,因此,方法重写没有意义。

但是,如果MyClass在运行时是一个调用方法的对象,这是可能的,就像在Smalltalk(或者可能是一个评论建议的JRuby,但我对JRuby一无所知)。

哦是的…还有一件事。您可以通过对象obj1.staticMethod()调用静态方法,但这实际上是MyClass.staticMethod()的语法糖,应该避免。在现代IDE中,它通常会引发一个警告。我不知道他们为什么允许走这条捷径。