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

如果可能,请举例说明。


当前回答

其实我们错了。 尽管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

;)

其他回答

我个人认为这是Java设计中的一个缺陷。是的,是的,我理解非静态方法附加到实例,而静态方法附加到类,等等。不过,考虑下面的代码:

public class RegularEmployee {
    private BigDecimal salary;

    public void setSalary(BigDecimal salary) {
        this.salary = salary;
    }

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

    public BigDecimal calculateBonus() {
        return salary.multiply(getBonusMultiplier());
    }

    /* ... presumably lots of other code ... */
}

public class SpecialEmployee extends RegularEmployee {
    public static BigDecimal getBonusMultiplier() {
        return new BigDecimal(".03");
    }
}

这段代码不能像您期望的那样工作。也就是说,特殊员工和普通员工一样有2%的奖金。但如果你去掉了“静态”,那么SpecialEmployee就能得到3%的奖金。

(不可否认,这个例子的编码风格很差,因为在现实生活中,你可能希望奖励乘数在数据库的某个地方,而不是硬编码。但这只是因为我不想用大量与主题无关的代码使示例陷入困境。)

在我看来,您可能想要使getBonusMultiplier成为静态的,这似乎很合理。也许您希望能够显示所有员工类别的奖金乘数,而不需要在每个类别中有一个员工实例。搜索这样的例子有什么意义呢?如果我们正在创建一个新的员工类别,并且还没有任何员工分配给它,该怎么办?这在逻辑上是一个静态函数。

但这并不奏效。

是的,是的,我可以想出很多方法来重写上面的代码,让它工作。我的观点不是它产生了一个无法解决的问题,而是它为粗心的程序员制造了一个陷阱,因为这种语言的行为不像我认为一个理性的人所期望的那样。

也许如果我试着为OOP语言编写一个编译器,我很快就会明白为什么实现它以覆盖静态函数是困难的或不可能的。

或许有一些很好的理由来解释为什么Java会这样做。有人能指出这种行为的好处吗,这种行为能让一些问题变得更简单吗?我的意思是,不要只是把我指给Java语言规范,然后说“看,这是它如何行为的文档”。我知道。但是,它为什么会有这样的表现,有一个很好的理由吗?(除了明显的“让它正常工作太难了”……)

更新

@VicKirk: If you mean that this is "bad design" because it doesn't fit how Java handles statics, my reply is, "Well, duh, of course." As I said in my original post, it doesn't work. But if you mean that it is bad design in the sense that there would be something fundamentally wrong with a language where this worked, i.e. where statics could be overridden just like virtual functions, that this would somehow introduce an ambiguity or it would be impossible to implement efficiently or some such, I reply, "Why? What's wrong with the concept?"

I think the example I give is a very natural thing to want to do. I have a class that has a function that does not depend on any instance data, and which I might very reasonably want to call independent of an instance, as well as wanting to call from within an instance method. Why should this not work? I've run into this situation a fair number of times over the years. In practice I get around it by making the function virtual, and then creating a static method whose only purpose in life is to be a static method that passes the call on to the virtual method with a dummy instance. That seems like a very roundabout way to get there.

Overriding in Java simply means that the particular method would be called based on the runtime type of the object and not on the compile-time type of it (which is the case with overridden static methods). As static methods are class methods they are not instance methods so they have nothing to do with the fact which reference is pointing to which Object or instance, because due to the nature of static method it belongs to a specific class. You can redeclare it in the subclass but that subclass won't know anything about the parent class' static methods because, as I said, it is specific to only that class in which it has been declared. 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 more details and example http://faisalbhagat.blogspot.com/2014/09/method-overriding-and-method-hiding.html

Yes. Practically Java allows overriding static method, and No theoretically if you Override a static method in Java then it will compile and run smoothly but it will lose Polymorphism which is the basic property of Java. You will Read Everywhere that it is not possible to try yourself compiling and running. you will get your answer. e.g. If you Have Class Animal and a static method eat() and you Override that static method in its Subclass lets called it Dog. Then when wherever you Assign a Dog object to an Animal Reference and call eat() according to Java Dog's eat() should have been called but in static Overriding Animals' eat() will Be Called.

class Animal {
    public static void eat() {
        System.out.println("Animal Eating");
    }
}

class Dog extends Animal{
    public static void eat() {
        System.out.println("Dog Eating");
    }
}

class Test {
    public static void main(String args[]) {
       Animal obj= new Dog();//Dog object in animal
       obj.eat(); //should call dog's eat but it didn't
    }
}


Output Animal Eating

According to Polymorphism Principle of Java, the Output Should be Dog Eating. But the result was different because to support Polymorphism Java uses Late Binding that means methods are called only at the run-time but not in the case of static methods. In static methods compiler calls methods at the compile time rather than the run-time, so we get methods according to the reference and not according to the object a reference a containing that's why You can say Practically it supports static overring but theoretically, it doesn't.

重写静态方法有什么好处呢?不能通过实例调用静态方法。

MyClass.static1()
MySubClass.static1()   // If you overrode, you have to call it through MySubClass anyway.

编辑:似乎由于语言设计中的一个不幸疏忽,您可以通过实例调用静态方法。一般没人会这么做。我的坏。

重写是为实例成员保留的,以支持多态行为。静态类成员不属于特定实例。相反,静态成员属于类,因此不支持重写,因为子类只继承受保护和公共实例成员,而不继承静态成员。您可能希望定义一个接口,并研究工厂和/或策略设计模式,以评估替代方法。