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

如果可能,请举例说明。


当前回答

I like and double Jay's comment (https://stackoverflow.com/a/2223803/1517187). I agree that this is the bad design of Java. Many other languages support overriding static methods, as we see in previous comments. I feel Jay has also come to Java from Delphi like me. Delphi (Object Pascal) was one of the languages implementing OOP before Java and one of the first languages used for commercial application development. It is obvious that many people had experience with that language since it was in the past the only language to write commercial GUI products. And - yes, we could in Delphi override static methods. Actually, static methods in Delphi are called "class methods", while Delphi had the different concept of "Delphi static methods" which were methods with early binding. To override methods you had to use late binding, declare "virtual" directive. So it was very convenient and intuitive and I would expect this in Java.

其他回答

简短的回答是:这是完全可能的,但Java没有做到。

下面是一些代码,说明了Java中的当前状态:

文件Base.java:

package sp.trial;
public class Base {
  static void printValue() {
    System.out.println("  Called static Base method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Base method.");
  }
  void nonLocalIndirectStatMethod() {
    System.out.println("  Non-static calls overridden(?) static:");
    System.out.print("  ");
    this.printValue();
  }
}

文件Child.java:

package sp.trial;
public class Child extends Base {
  static void printValue() {
    System.out.println("  Called static Child method.");
  }
  void nonStatPrintValue() {
    System.out.println("  Called non-static Child method.");
  }
  void localIndirectStatMethod() {
    System.out.println("  Non-static calls own static:");
    System.out.print("  ");
    printValue();
  }
  public static void main(String[] args) {
    System.out.println("Object: static type Base; runtime type Child:");
    Base base = new Child();
    base.printValue();
    base.nonStatPrintValue();
    System.out.println("Object: static type Child; runtime type Child:");
    Child child = new Child();
    child.printValue();
    child.nonStatPrintValue();
    System.out.println("Class: Child static call:");
    Child.printValue();
    System.out.println("Class: Base static call:");
    Base.printValue();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Child:");
    child.localIndirectStatMethod();
    System.out.println("Object: static/runtime type Child -- call static from non-static method of Base:");
    child.nonLocalIndirectStatMethod();
  }
}

如果你运行这个(我在Mac上做的,从Eclipse,使用Java 1.6),你会得到:

Object: static type Base; runtime type Child.
  Called static Base method.
  Called non-static Child method.
Object: static type Child; runtime type Child.
  Called static Child method.
  Called non-static Child method.
Class: Child static call.
  Called static Child method.
Class: Base static call.
  Called static Base method.
Object: static/runtime type Child -- call static from non-static method of Child.
  Non-static calls own static.
    Called static Child method.
Object: static/runtime type Child -- call static from non-static method of Base.
  Non-static calls overridden(?) static.
    Called static Base method.

在这里,唯一可能令人惊讶的情况(也是这个问题所涉及的)似乎是第一种情况:

运行时类型并不用于确定调用哪些静态方法,即使是在使用对象实例(obj.staticMethod())调用时也是如此。

最后一种情况:

当从类的对象方法中调用静态方法时,选择的静态方法是类本身可访问的方法,而不是定义对象运行时类型的类可访问的方法。

使用对象实例调用

静态调用在编译时解析,而非静态方法调用在运行时解析。注意,尽管静态方法是继承的(从父方法),但它们不会被(子方法)覆盖。如果你另有期待,这可能会是一个惊喜。

从对象方法中调用

对象方法调用使用运行时类型解析,但静态(类)方法调用使用编译时(已声明)类型解析。

改变规则

要更改这些规则,以便示例中的最后一个调用Child.printValue(),静态调用必须在运行时提供类型,而不是编译器在编译时使用对象(或上下文)声明的类解析调用。然后,静态调用可以使用(动态)类型层次结构来解析调用,就像现在的对象方法调用一样。

这是很容易做到的(如果我们改变Java:-O),并不是完全不合理的,然而,它有一些有趣的考虑。

主要需要考虑的是,我们需要决定哪个静态方法调用应该执行此操作。

目前,Java语言中有这种“怪癖”,即obj.staticMethod()调用被ObjectClass.staticMethod()调用取代(通常带有警告)。[注意:ObjectClass是obj的编译时类型。]这些将是很好的候选人,以这种方式重写,采用obj的运行时类型。

如果我们这样做了,就会使方法体更难阅读:父类中的静态调用可能会被动态地“重新路由”。为了避免这种情况,我们必须使用类名调用静态方法——这使得调用更明显地用编译时类型层次结构来解析(就像现在一样)。

调用静态方法的其他方法更加棘手:this. staticmethod()的意思应该与obj.staticMethod()相同,接受this的运行时类型。然而,这可能会给现有程序带来一些麻烦,这些程序调用(显然是本地的)没有修饰的静态方法(可以说相当于this.method())。

那么无修饰调用staticMethod()会怎样呢?我建议他们像今天一样,使用本地类上下文来决定要做什么。否则就会产生巨大的混乱。当然,如果method是非静态方法,则method()意味着this.method(),如果method是静态方法,则意味着ThisClass.method()。这是另一个困惑的来源。

其他的考虑

如果我们改变了这种行为(并使静态调用具有潜在的动态非本地性),我们可能会希望重新审视final、private和protected作为类静态方法的限定符的意义。然后,我们都必须习惯这样一个事实:私有静态方法和公共final方法不会被覆盖,因此可以在编译时安全地解析,并且可以“安全”地作为本地引用读取。

下面的代码表明这是可能的:

class OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriden Meth");   
}   

}   

public class OverrideStaticMeth extends OverridenStaticMeth {   

static void printValue() {   
System.out.println("Overriding Meth");   
}   

public static void main(String[] args) {   
OverridenStaticMeth osm = new OverrideStaticMeth();   
osm.printValue();   

System.out.println("now, from main");
printValue();

}   

} 

静态方法、变量、块或嵌套类属于整个类而不是对象。

Java中的方法用于公开对象/类的行为。在这里,由于方法是静态的(即静态方法仅用于表示类的行为),改变/覆盖整个类的行为将违反面向对象编程的基本支柱之一,即高内聚。(记住构造函数在Java中是一种特殊的方法。)

高内聚性——一个类应该只有一个角色。例如:car类应该只生成汽车对象,而不生成自行车、卡车、飞机等。但是Car类可能有一些只属于它自己的特性(行为)。

因此,在设计java编程语言时。语言设计者认为,只有通过使方法本质上是静态的,才能允许开发人员保留类的某些行为。


下面的代码尝试覆盖静态方法,但不会遇到任何编译错误。

public class Vehicle {
static int VIN;

public static int getVehileNumber() {
    return VIN;
}}

class Car extends Vehicle {
static int carNumber;

public static int getVehileNumber() {
    return carNumber;
}}

这是因为,在这里我们没有重写一个方法,而只是重新声明它。Java允许重新声明一个方法(静态/非静态)。

从Car类的getVehileNumber()方法中删除静态关键字将导致编译错误,因为,我们正在尝试改变只属于Vehicle类的静态方法的功能。

此外,如果getVehileNumber()被声明为final,那么代码将无法编译,因为final关键字限制程序员重新声明方法。

public static final int getVehileNumber() {
return VIN;     }

总的来说,这取决于软件设计人员在哪里使用静态方法。 我个人更喜欢使用静态方法来执行某些操作,而不需要创建类的任何实例。第二,对外界隐藏一个类的行为。

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

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

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