为什么Java不允许重写静态方法?

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

如果可能,请举例说明。

291479 次浏览

重写依赖于类的实例。多态性的意义在于,您可以子类化一个类,而实现这些子类的对象对于父类中定义的相同方法将具有不同的行为(并且在子类中被重写)。静态方法不与类的任何实例相关联,因此这个概念不适用。

驱动Java设计的两个考虑因素影响了这一点。一个是对性能的担忧:有很多人批评Smalltalk太慢(垃圾收集和多态调用是其中的一部分),而Java的创建者决心避免这种情况。另一个原因是Java的目标受众是c++开发人员。让静态方法以它们所做的方式工作,对c++程序员有好处,也非常快,因为不需要等到运行时才知道要调用哪个方法。

静态方法被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()。静态方法不绑定到对象,因此静态方法中没有thissuper的概念。静态方法是一个全局函数;因此,也没有多态性的概念,因此,方法重写没有意义。

但是,如果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%的奖金。但如果你去掉了“静态”,那么SpecialEmployee就能得到3%的奖金。

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

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

但这并不奏效。

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

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

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

更新

@VicKirk:如果你的意思是这是“糟糕的设计”,因为它不符合Java处理静态的方式,我的回答是,“嗯,当然。”正如我在最初的帖子中所说的,这是行不通的。但如果你的意思是这是一种糟糕的设计,从某种意义上说,这是一种语言的根本错误,即静态函数可以像虚函数一样被覆盖,这将以某种方式引入模糊性,或者不可能有效地实现或诸如此类,我会回答,“为什么?这个概念有什么问题?”

我认为我举的例子是很自然的事情。我有一个类,它有一个不依赖于任何实例数据的函数,我可能非常合理地希望独立于实例调用它,也希望从实例方法中调用它。为什么这行不通呢?这些年来,我遇到过很多次这种情况。在实践中,我通过将函数设为虚函数来解决这个问题,然后创建一个静态方法,该方法的唯一目的是将调用传递给带有虚拟实例的虚方法。这似乎是一种非常迂回的方式。

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

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

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

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

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

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

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

我不太了解Ruby,正如OP提到的,我做了一些研究。我发现在Ruby中,类实际上是一种特殊的对象,人们可以(甚至动态地)创建新的方法。在Ruby中,类是完整的类对象,而在Java中不是。这是您在使用Java(或c#)时必须接受的一点。这些都不是动态语言,尽管c#添加了一些形式的动态语言。实际上,据我所知,Ruby并没有“静态”方法——在这种情况下,这些方法都是在单例类对象上。然后,您可以用一个新类重写这个单例,并且前一个类对象中的方法将调用新类中定义的方法(正确吗?)因此,如果你在原始类的上下文中调用一个方法,它仍然只会执行原始的静态,但在派生类中调用一个方法,将调用来自父类或子类的方法。很有趣,我可以从中看到一些价值。这需要一种不同的思维模式。

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

编辑:另一个评论。现在我看到了差异,作为Java/ c#开发人员,我可以理解为什么如果你来自像Ruby这样的语言,你从Java开发人员那里得到的答案可能会令人困惑。Java static方法与Ruby class方法不同。Java开发人员将很难理解这一点,相反,那些主要使用Ruby/Smalltalk等语言的人也很难理解这一点。我知道这也会让人非常困惑,因为Java也使用“类方法”作为谈论静态方法的另一种方式,但Ruby使用相同的术语是不同的。Java没有Ruby风格的类方法(抱歉);Ruby没有Java风格的静态方法,这些方法实际上只是C中发现的旧的过程式函数。

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

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

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!"

尽管lassiekermit都声明为Animal类型的对象,但它们的行为(方法.speak())会发生变化,因为动态调度只会在运行时将绑定方法调用.speak()到实现,而不是在编译时。

所以你不能覆盖静态方法的原因是静态成员上没有动态调度-如果他们动态调度(因此可以被覆盖),static关键字就没有意义了。

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

下面是一些代码,说明了Java中的current state of affairs:

文件# EYZ0:

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

文件# EYZ0:

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()调用取代(通常带有警告)。注意: ObjectClassobj的编译时类型。这些将是很好的以这种方式重写的候选者,采用obj的运行时类型。

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

调用静态方法的其他方法更加棘手:this.staticMethod()的意思应该与obj.staticMethod()相同,采用this的运行时类型。然而,对于现有的程序来说,这可能会导致一些令人头疼的问题,这些程序调用(显然是本地的)没有修饰的静态方法(可以说相当于this.method())。

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

其他的考虑

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

嗯…如果从Java中重写方法应该如何表现的角度考虑,答案是否定的。但是,如果您尝试重写静态方法,则不会得到任何编译器错误。这意味着,如果你试图重写,Java不会阻止你这么做;但是你肯定不会得到与非静态方法相同的效果。在Java中重写仅仅意味着将基于对象的运行时类型调用特定的方法,而不是基于它的编译时类型(重载静态方法就是这种情况)。好吧……有没有人能猜出它们行为怪异的原因?因为它们是类方法,因此对它们的访问总是在编译时仅使用编译时类型信息进行解析。使用对象引用访问它们只是Java设计者给予的额外自由,我们当然不应该认为只有当他们限制它时才停止这种做法:-)

< /强> < >强例子:让我们试着看看如果我们尝试重写一个静态方法会发生什么:-

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();
// ...
}
}
< p > # EYZ0: - < br > # EYZ0 < br > # EYZ0 < br > # EYZ0 < / p >

注意输出的第二行。如果staticMethod被重写,这一行应该与第三行相同,因为我们在运行时类型的对象上调用'staticMethod()'作为'子类'而不是'超类'。这证实了静态方法总是只使用它们的编译时类型信息进行解析。

我喜欢Jay的评论(https://stackoverflow.com/a/2223803/1517187) 我同意这是Java的糟糕设计 正如我们在前面的评论中看到的,许多其他语言支持覆盖静态方法。 我觉得Jay也像我一样从Delphi来到Java Delphi (Object Pascal)是在Java之前实现OOP的语言之一,也是最早用于商业应用程序开发的语言之一 很明显,许多人都有使用这种语言的经验,因为它是过去编写商业GUI产品的唯一语言。是的,我们可以在Delphi中重写静态方法。实际上,Delphi中的静态方法被称为“类方法”,而Delphi则有不同的概念“Delphi静态方法”。这些都是早期绑定的方法。要覆盖必须使用后期绑定的方法,请声明“virtual”;指令。所以这是非常方便和直观的,我希望这在Java中

其实我们错了 尽管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不支持静态方法重写。

通过覆盖,您实现了动态多态性。 当你说覆盖静态方法时,你试图使用的词是矛盾的。

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

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

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

注意:即使你用一个对象访问一个类方法,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!";
}


}
在Java中重写仅仅意味着将基于运行时类型调用特定的方法 对象的编译时类型,而不是对象的编译时类型(这是覆盖静态方法的情况)。由于静态方法是类方法,它们不是实例方法,因此它们与哪个引用指向哪个对象或实例无关,因为由于静态方法的性质,它属于特定的类。你可以在子类中重新声明它,但是那个子类不知道父类的静态方法,因为,正如我说的,它只特定于它被声明的那个类。使用对象引用访问它们只是Java设计者给予的额外自由,我们当然不应该认为只有当他们限制它时才停止这种做法 更多细节和示例 # EYZ0 < / p >

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

这里有一个简单的解释。静态方法与类相关联,而实例方法与特定对象相关联。覆盖允许调用与特定对象关联的被覆盖方法的不同实现。因此,重写静态方法是违反直觉的,因为它甚至不与对象相关联,而是与类本身相关联。因此,静态方法不能基于调用它的对象来重写,它总是与创建它的类相关联。

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

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关键字限制程序员重新声明方法。

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

查看Java oracle文档和搜索你可以在子类中做什么来了解子类中隐藏静态方法的详细信息。

谢谢

是的。实际上Java允许重写静态方法,理论上如果你在Java中重写一个静态方法,那么它将编译和运行顺畅,但它将失去多态性,这是Java的基本属性。你会读到到处都是不可能自己编译和运行的东西。你会得到答案的。例:如果你有Animal类和一个静态方法eat(),你在它的子类中重写了这个静态方法,叫它Dog。然后,当你将一个Dog对象分配给一个Animal引用并根据Java调用eat()时,Dog的eat()应该已经被调用,但在静态中重写Animals的eat()将被调用。

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

根据Java的多态原理,Output应该是Dog Eating 但是结果是不同的,因为为了支持多态性,Java使用了后期绑定,这意味着方法只在运行时调用,而不是在静态方法的情况下调用。在静态方法中,编译器在编译时而不是在运行时调用方法,因此我们根据引用而不是根据对象引用来获取方法,这就是为什么你可以说实际上它支持静态覆盖,但理论上它不支持