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

如果可能,请举例说明。


当前回答

这个问题的答案很简单,标记为静态的方法或变量只属于类,因此静态方法不能在子类中继承,因为它们只属于超类。

其他回答

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

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

简单的解决方案:使用单例实例。它将允许重写和继承。

在我的系统中,我有SingletonsRegistry类,它为传递的class返回实例。如果没有找到instance,则创建它。

Haxe语言类:

package rflib.common.utils;
import haxe.ds.ObjectMap;



class SingletonsRegistry
{
  public static var instances:Map<Class<Dynamic>, Dynamic>;

  static function __init__()
  {
    StaticsInitializer.addCallback(SingletonsRegistry, function()
    {
      instances = null;
    });

  } 

  public static function getInstance(cls:Class<Dynamic>, ?args:Array<Dynamic>)
  {
    if (instances == null) {
      instances = untyped new ObjectMap<Dynamic, Dynamic>();      
    }

    if (!instances.exists(cls)) 
    {
      if (args == null) args = [];
      instances.set(cls, Type.createInstance(cls, args));
    }

    return instances.get(cls);
  }


  public static function validate(inst:Dynamic, cls:Class<Dynamic>)
  {
    if (instances == null) return;

    var inst2 = instances[cls];
    if (inst2 != null && inst != inst2) throw "Can\'t create multiple instances of " + Type.getClassName(cls) + " - it's singleton!";
  }

}

通过重写,可以实现动态多态。 当您说覆盖静态方法时,您试图使用的词语是矛盾的。

静态表示-编译时,重写用于动态多态性。 两者在性质上是相反的,因此不能同时使用。

动态多态行为发生在程序员使用对象并访问实例方法时。JRE将根据您使用的对象类型映射不同类的不同实例方法。

当你说覆盖静态方法时,我们将使用类名访问静态方法,它将在编译时被链接,因此没有在运行时将方法与静态方法链接的概念。因此,术语“重写”静态方法本身没有任何意义。

注意:即使你用一个对象访问一个类方法,java编译器仍然有足够的智能来发现它,并会做静态链接。

在Java(和许多面向对象语言,但我不能说所有;所有的方法都有一个固定的签名——参数和类型。在虚方法中,第一个参数是隐含的:对对象本身的引用,当从对象内部调用时,编译器会自动添加这个参数。

静态方法没有区别——它们仍然有固定的签名。然而,通过将方法声明为静态,您已经显式地声明了编译器不能在该签名的开头包含隐含的对象形参。因此,任何其他调用此方法的代码都不能试图将对象引用放到堆栈上。如果它确实这样做了,那么方法执行将无法工作,因为参数将在堆栈上的错误位置—移位1。

由于两者之间的差异;虚方法总是有一个上下文对象的引用(即this),这样就可以引用堆中属于该对象实例的任何东西。但是对于静态方法,由于没有传递引用,该方法不能访问任何对象变量和方法,因为上下文是未知的。

如果您希望Java更改定义,以便为每个方法(静态方法或虚拟方法)传递对象上下文,那么实际上您将只有虚拟方法。

就像有人在评论中问的那样——你想要这个功能的原因和目的是什么?

I do not know Ruby much, as this was mentioned by the OP, I did some research. I see that in Ruby classes are really a special kind of object and one can create (even dynamically) new methods. Classes are full class objects in Ruby, they are not in Java. This is just something you will have to accept when working with Java (or C#). These are not dynamic languages, though C# is adding some forms of dynamic. In reality, Ruby does not have "static" methods as far as I could find - in that case these are methods on the singleton class object. You can then override this singleton with a new class and the methods in the previous class object will call those defined in the new class (correct?). So if you called a method in the context of the original class it still would only execute the original statics, but calling a method in the derived class, would call methods either from the parent or sub-class. Interesting and I can see some value in that. It takes a different thought pattern.

由于您正在使用Java工作,您将需要适应这种做事方式。他们为什么这么做?好吧,可能是为了提高当时的性能基于现有的技术和理解。计算机语言在不断发展。回顾过去,并没有OOP这种东西。在未来,还会有其他新的想法。

EDIT: One other comment. Now that I see the differences and as I Java/C# developer myself, I can understand why the answers you get from Java developers may be confusing if you are coming from a language like Ruby. Java static methods are not the same as Ruby class methods. Java developers will have a hard time understanding this, as will conversely those who work mostly with a language like Ruby/Smalltalk. I can see how this would also be greatly confusing by the fact that Java also uses "class method" as another way to talk about static methods but this same term is used differently by Ruby. Java does not have Ruby style class methods (sorry); Ruby does not have Java style static methods which are really just old procedural style functions, as found in C.

顺便说一下,谢谢你的问题!今天我学到了一些关于类方法的新知识(Ruby风格)。

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

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;     }

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