为什么';Java是否允许重写静态方法?

为什么';Java是否允许重写静态方法?,java,static,overriding,static-methods,Java,Static,Overriding,Static Methods,为什么不可能重写静态方法 如果可能,请使用一个示例。重写取决于拥有一个类的实例。多态性的要点是,您可以对一个类进行子类化,而实现这些子类的对象对于在超类中定义(并在子类中重写)的相同方法将具有不同的行为。静态方法不与类的任何实例关联,因此该概念不适用 Java的设计中有两个考虑因素影响了这一点。一个是性能问题:有很多人批评Smalltalk太慢(垃圾收集和多态调用就是其中的一部分),Java的创建者决心避免这种情况。另一个是java的目标受众是C++开发者的决定。让静态方法工作起来,有利于C++

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


如果可能,请使用一个示例。

重写取决于拥有一个类的实例。多态性的要点是,您可以对一个类进行子类化,而实现这些子类的对象对于在超类中定义(并在子类中重写)的相同方法将具有不同的行为。静态方法不与类的任何实例关联,因此该概念不适用


Java的设计中有两个考虑因素影响了这一点。一个是性能问题:有很多人批评Smalltalk太慢(垃圾收集和多态调用就是其中的一部分),Java的创建者决心避免这种情况。另一个是java的目标受众是C++开发者的决定。让静态方法工作起来,有利于C++程序员熟悉,而且速度非常快,因为不必等到运行时才知道调用哪种方法。

< P>静态方法被JVM视为全局的,根本没有绑定到对象实例。 从概念上讲,如果可以从类对象(如Smalltalk等语言)调用静态方法,这是可能的,但在Java中并非如此

编辑

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

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中,它通常会发出警告。我不知道他们为什么会允许这个快捷方式。

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

覆盖静态方法有什么好处。不能通过实例调用静态方法

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

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

我个人认为这是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%的奖金。但是如果你删除了“静态”,那么特殊员工将获得3%的奖金

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

在我看来,您可能希望将getBonusMultiplier设置为静态似乎很有道理。也许您希望能够显示所有类别员工的奖金乘数,而不需要在每个类别中都有一个员工实例。搜索这样的实例有什么意义?如果我们正在创建一个新的员工类别,但尚未分配任何员工,该怎么办?这在逻辑上是一个静态函数

但它不起作用

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

也许如果我尝试为OOP语言编写一个编译器,我会很快明白为什么实现它以便重写静态函数会很困难或不可能

或者,也许有一些很好的理由可以解释为什么Java会这样做。有人能指出这种行为的一个优点吗?这种行为使某些类型的问题变得更容易?我的意思是,不要只是指给我看Java语言规范,然后说“看,这是记录它的行为的”。我知道。但是,有没有一个很好的理由让它这样做呢?(除了明显的“让它正常工作太难了”…)

更新

@维克:如果你的意思是这是“糟糕的设计”,因为它不适合Java处理静态的方式,那么我的回答是,“嗯,是的,当然。”正如我在最初的帖子中所说,它不起作用。但是,如果你的意思是,这是一种糟糕的设计,从某种意义上说,这种设计的语言可能存在根本性的错误,也就是说,静态可以像虚拟函数一样被重写,这会以某种方式引入歧义,或者不可能有效地实现,或者类似的情况,
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();

}   

} 
Animal lassie = new Dog();
lassie.speak(); // outputs "woof!"
Animal kermit = new Frog();
kermit.speak(); // outputs "ribbit!"
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();
  }
}
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();
  }
}
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.
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();
    // ...
}
}
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
RegularEmployee Carl = new SpecialEmployee();

System.out.println(Carl.calculateBonus());
System.out.println(Carl.calculateOverridenBonus());
0.02
0.03
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!";
  }

}
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;
}}
public static final int getVehileNumber() {
return VIN;     }
public class StaticMethodsHiding {
    public static void main(String[] args) {
        SubClass.hello();
    }
}


class SuperClass {
    static void hello(){
        System.out.println("SuperClass saying Hello");
    }
}


class SubClass extends SuperClass {
    // static void hello() {
    // System.out.println("SubClass Hello");
    // }
}
SuperClass saying Hello
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