为什么';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