为什么 Java 不允许重写静态方法?
为什么不能重写静态方法?
如果可能,请使用示例。
Why is it not possible to override static methods?
If possible, please use an example.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为什么不能重写静态方法?
如果可能,请使用示例。
Why is it not possible to override static methods?
If possible, please use an example.
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(22)
重写取决于是否有类的实例。多态性的要点是,您可以对一个类进行子类化,并且实现这些子类的对象对于超类中定义的相同方法(并在子类中重写)将具有不同的行为。静态方法不与类的任何实例关联,因此该概念不适用。
Java 的设计有两个考虑因素影响了这一点。其中之一是对性能的担忧:Smalltalk 受到了很多批评,认为它太慢(垃圾收集和多态调用是其中的一部分),而 Java 的创建者决心避免这种情况。另一个决定是 Java 的目标受众是 C++ 开发人员。让静态方法按照其实际方式工作有利于 C++ 程序员熟悉,而且速度也非常快,因为无需等到运行时才确定要调用哪个方法。
Overriding depends on having an instance of a class. The point of polymorphism is that you can subclass a class and the objects implementing those subclasses will have different behaviors for the same methods defined in the superclass (and overridden in the subclasses). A static method is not associated with any instance of a class so the concept is not applicable.
There were two considerations driving Java's design that impacted this. One was a concern with performance: there had been a lot of criticism of Smalltalk about it being too slow (garbage collection and polymorphic calls being part of that) and Java's creators were determined to avoid that. Another was the decision that the target audience for Java was C++ developers. Making static methods work the way they do had the benefit of familiarity for C++ programmers and was also very fast, because there's no need to wait until runtime to figure out which method to call.
我个人认为这是Java设计上的一个缺陷。是的,是的,我知道非静态方法附加到实例,而静态方法附加到类,等等。不过,请考虑以下代码:
此代码将不会按您的预期工作。即,特殊员工与普通员工一样获得 2% 的奖金。但如果你删除“静态”,那么 SpecialEmployee 就会获得 3% 的奖金。
(诚然,这个例子的编码风格很差,因为在现实生活中,你可能希望奖金乘数位于数据库中的某个地方,而不是硬编码。但这只是因为我不想让这个例子陷入困境与要点无关的代码。)
在我看来,您可能希望将 getBonusMultiplier 设为静态,这似乎很合理。也许您希望能够显示所有员工类别的奖金乘数,而不需要每个类别中都有一个员工实例。搜索此类示例实例的意义何在?如果我们正在创建一个新的员工类别,但尚未分配任何员工,该怎么办?从逻辑上讲,这是一个静态函数。
但这不起作用。
是的,是的,我可以想出多种方法来重写上面的代码以使其工作。我的观点并不是说它造成了一个无法解决的问题,而是它为粗心的程序员制造了一个陷阱,因为该语言的行为并不像我认为一个理性的人所期望的那样。
也许如果我尝试为 OOP 语言编写一个编译器,我很快就会明白为什么实现它以重写静态函数会很困难或不可能。
或者也许 Java 的行为方式有一些充分的理由。任何人都可以指出这种行为的优点,从而使某些类别的问题变得更容易吗?我的意思是,不要只是向我指出 Java 语言规范并说“看,这已记录了它的行为方式”。我知道。但它应该这样做有充分的理由吗? (除了明显的“让它正常工作太难了”......)
更新
@VicKirk:如果你的意思是这是“糟糕的设计”,因为它不适合 Java 处理静态的方式,我的回答是:“嗯,当然了。”正如我在原来的帖子中所说,它不起作用。但是,如果您的意思是这是糟糕的设计,因为这种设计有效的语言存在根本性错误,即静态变量可以像虚函数一样被重写,那么这会以某种方式引入歧义,或者不可能有效实施或类似的,我回答,“为什么?这个概念有什么问题?”
我认为我给出的例子是很自然的事情。我有一个类,它的函数不依赖于任何实例数据,并且我可能非常合理地希望独立于实例进行调用,并且希望从实例方法中进行调用。为什么这不起作用?多年来我多次遇到这种情况。在实践中,我通过将函数设为虚拟,然后创建一个静态方法来解决这个问题,该静态方法的唯一目的是成为一个静态方法,将调用传递给带有虚拟实例的虚拟方法。这似乎是一种非常迂回的方式。
Personally I think this is a flaw in the design of Java. Yes, yes, I understand that non-static methods are attached to an instance while static methods are attached to a class, etc etc. Still, consider the following code:
This code will not work as you might expect. Namely, SpecialEmployee's get a 2% bonus just like regular employees. But if you remove the "static"s, then SpecialEmployee's get a 3% bonus.
(Admittedly, this example is poor coding style in that in real life you would likely want the bonus multiplier to be in a database somewhere rather than hard-coded. But that's just because I didn't want to bog down the example with a lot of code irrelevant to the point.)
It seems quite plausible to me that you might want to make getBonusMultiplier static. Perhaps you want to be able to display the bonus multiplier for all the categories of employees, without needing to have an instance of an employee in each category. What would be the point of searching for such example instances? What if we are creating a new category of employee and don't have any employees assigned to it yet? This is quite logically a static function.
But it doesn't work.
And yes, yes, I can think of any number of ways to rewrite the above code to make it work. My point is not that it creates an unsolvable problem, but that it creates a trap for the unwary programmer, because the language does not behave as I think a reasonable person would expect.
Perhaps if I tried to write a compiler for an OOP language, I would quickly see why implementing it so that static functions can be overriden would be difficult or impossible.
Or perhaps there is some good reason why Java behaves this way. Can anyone point out an advantage to this behavior, some category of problem that is made easier by this? I mean, don't just point me to the Java language spec and say "see, this is documented how it behaves". I know that. But is there a good reason why it SHOULD behave this way? (Besides the obvious "making it work right was too hard"...)
Update
@VicKirk: If you mean that this is "bad design" because it doesn't fit how Java handles statics, my reply is, "Well, duh, of course." As I said in my original post, it doesn't work. But if you mean that it is bad design in the sense that there would be something fundamentally wrong with a language where this worked, i.e. where statics could be overridden just like virtual functions, that this would somehow introduce an ambiguity or it would be impossible to implement efficiently or some such, I reply, "Why? What's wrong with the concept?"
I think the example I give is a very natural thing to want to do. I have a class that has a function that does not depend on any instance data, and which I might very reasonably want to call independent of an instance, as well as wanting to call from within an instance method. Why should this not work? I've run into this situation a fair number of times over the years. In practice I get around it by making the function virtual, and then creating a static method whose only purpose in life is to be a static method that passes the call on to the virtual method with a dummy instance. That seems like a very roundabout way to get there.
简短的回答是:这是完全可能的,但 Java 没有这样做。
下面是一些代码,说明了 Java 中的当前状态:
File
Base.java
:File
Child.java
:如果你运行这个(我在 Mac 上运行,从 Eclipse,使用 Java 1.6),你会得到:
Here, the only 可能令人惊讶的情况(以及问题所涉及的情况)出现第一种情况:
“运行时类型不用于确定调用哪些静态方法,即使使用对象实例调用 (
obj.staticMethod()
)”。以及最后情况:
“当从类的对象方法中调用静态方法时,选择的静态方法是可以从类本身访问的方法,而不能从定义对象的运行时类型的类。”
使用对象实例进行调用
静态调用在编译时解析,而非静态方法调用在运行时解析。请注意,虽然静态方法是(从父级)继承的,但它们不会(由子级)重写。如果您另有预期,这可能会令人惊讶。
从对象方法内部调用
对象方法调用使用运行时类型解析,但静态(类)方法调用使用编译时(声明)类型解析。
更改规则
要更改这些规则,以便示例中的最后一个调用称为
Child.printValue()
,静态调用必须在运行时提供类型,而不是由编译器解析在编译时使用对象(或上下文)的声明类进行调用。然后,静态调用可以使用(动态)类型层次结构来解析调用,就像今天的对象方法调用一样。这很容易实现(如果我们改变 Java :-O),并且一点也不合理,但是,它有一些有趣的考虑。
主要考虑因素是我们需要决定哪个静态方法调用应该执行此操作。
目前,Java 在语言中存在这样的“怪癖”,即
obj.staticMethod()
调用被ObjectClass.staticMethod()
调用替换(通常带有警告)。 [注意:ObjectClass
是obj
的编译时类型。] 这些将是以这种方式覆盖的良好候选者,采取运行-obj
的时间类型。如果我们这样做,就会使方法体更难阅读:父类中的静态调用可能会动态“重新路由”。为了避免这种情况,我们必须使用类名调用静态方法——这使得使用编译时类型层次结构更明显地解决了调用问题(就像现在一样)。
调用静态方法的其他方法更加棘手:
this.staticMethod()
应该与obj.staticMethod()
含义相同,采用运行时类型 <代码>这个。然而,这可能会给现有程序带来一些麻烦,这些程序调用(显然是本地的)静态方法而不进行修饰(这可以说相当于this.method()
)。那么朴素的调用
staticMethod()
又如何呢?我建议他们像今天一样,使用当地的班级背景来决定要做什么。否则就会造成极大的混乱。当然,如果method
是非静态方法,那么method()
就意味着this.method()
,并且ThisClass .method()
如果method
是静态方法。这是另一个混乱的根源。其他考虑因素
如果我们改变这种行为(并使静态调用可能动态地非本地),我们可能需要重新审视
final
、private
和protected 的含义
作为类的static
方法的限定符。然后我们都必须习惯这样一个事实:private static
和public final
方法不会被重写,因此可以在编译时安全地解析,并且是“安全”作为本地参考阅读。The short answer is: it is entirely possible, but Java doesn't do it.
Here is some code which illustrates the current state of affairs in Java:
File
Base.java
:File
Child.java
:If you run this (I did it on a Mac, from Eclipse, using Java 1.6) you get:
Here, the only cases which might be a surprise (and which the question is about) appear to be the first case:
"The run-time type is not used to determine which static methods are called, even when called with an object instance (
obj.staticMethod()
)."and the last case:
"When calling a static method from within an object method of a class, the static method chosen is the one accessible from the class itself and not from the class defining the run-time type of the object."
Calling with an object instance
The static call is resolved at compile-time, whereas a non-static method call is resolved at run-time. Notice that although static methods are inherited (from parent) they are not overridden (by child). This could be a surprise if you expected otherwise.
Calling from within an object method
Object method calls are resolved using the run-time type, but static (class) method calls are resolved using the compile-time (declared) type.
Changing the rules
To change these rules, so that the last call in the example called
Child.printValue()
, static calls would have to be provided with a type at run-time, rather than the compiler resolving the call at compile-time with the declared class of the object (or context). Static calls could then use the (dynamic) type hierarchy to resolve the call, just as object method calls do today.This would easily be doable (if we changed Java :-O), and is not at all unreasonable, however, it has some interesting considerations.
The main consideration is that we need to decide which static method calls should do this.
At the moment, Java has this "quirk" in the language whereby
obj.staticMethod()
calls are replaced byObjectClass.staticMethod()
calls (normally with a warning). [Note:ObjectClass
is the compile-time type ofobj
.] These would be good candidates for overriding in this way, taking the run-time type ofobj
.If we did it would make method bodies harder to read: static calls in a parent class could potentially be dynamically "re-routed". To avoid this we would have to call the static method with a class name -- and this makes the calls more obviously resolved with the compile-time type hierarchy (as now).
The other ways of invoking a static method are more tricky:
this.staticMethod()
should mean the same asobj.staticMethod()
, taking the run-time type ofthis
. However, this might cause some headaches with existing programs, which call (apparently local) static methods without decoration (which is arguably equivalent tothis.method()
).So what about unadorned calls
staticMethod()
? I suggest they do the same as today, and use the local class context to decide what to do. Otherwise great confusion would ensue. Of course it means thatmethod()
would meanthis.method()
ifmethod
was a non-static method, andThisClass.method()
ifmethod
were a static method. This is another source of confusion.Other considerations
If we changed this behaviour (and made static calls potentially dynamically non-local), we would probably want to revisit the meaning of
final
,private
andprotected
as qualifiers onstatic
methods of a class. We would then all have to get used to the fact thatprivate static
andpublic final
methods are not overridden, and can therefore be safely resolved at compile-time, and are "safe" to read as local references.其实我们错了。
尽管默认情况下 Java 不允许覆盖静态方法,但如果您仔细查看 Java 中的 Class 和 Method 类的文档,您仍然可以通过以下解决方法找到模拟静态方法覆盖的方法:
结果输出:
我们正在尝试的内容实现:)
即使我们将第三个变量 Carl 声明为 RegularEmployee 并将其分配给 SpecialEmployee 实例,我们仍然会在第一种情况下调用 RegularEmployee 方法,在第二种情况下调用 SpecialEmployee 方法,
只需查看输出控制台:
;)
Actually we were wrong.
Despite Java doesn't allow you to override static methods by default, if you look thoroughly through documentation of Class and Method classes in Java, you can still find a way to emulate static methods overriding by following workaround:
Resulting output:
what we were trying to achieve :)
Even if we declare third variable Carl as RegularEmployee and assign to it instance of SpecialEmployee, we will still have call of RegularEmployee method in first case and call of SpecialEmployee method in second case
just look at output console:
;)
静态方法被 JVM 视为全局方法,根本不绑定到对象实例。
如果您可以从类对象调用静态方法(就像在 Smalltalk 等语言中一样),那么从概念上讲这是可能的,但在 Java 中却并非如此。
编辑
您可以重载静态方法,没关系。但是您不能覆盖静态方法,因为类不是一流的对象。您可以使用反射在运行时获取对象的类,但是您获取的对象与类层次结构不平行。
你可以在课堂上进行反思,但也仅限于此。您不能使用
clazz1.staticMethod()
调用静态方法,而是使用MyClass.staticMethod()
来调用。静态方法不绑定到对象,因此静态方法中没有this
和super
的概念。静态方法是一个全局函数;因此,也没有多态性的概念,因此方法重写没有意义。但是,如果
MyClass
是一个运行时调用方法的对象,就像 Smalltalk 中那样(或者可能是 JRuby,正如一条评论所建议的那样,但我对 JRuby 一无所知),这也是可能的。哦,是的……还有一件事。您可以通过对象
obj1.staticMethod()
调用静态方法,但这实际上是MyClass.staticMethod()
的语法糖,应该避免。它通常会在现代 IDE 中发出警告。我不知道他们为什么允许这条捷径。Static methods are treated as global by the JVM, there are not bound to an object instance at all.
It could conceptually be possible if you could call static methods from class objects (like in languages like Smalltalk) but it's not the case in Java.
EDIT
You can overload static method, that's ok. But you can not override a static method, because class are no first-class object. You can use reflection to get the class of an object at run-time, but the object that you get does not parallel the class hierarchy.
You can reflect over the classes, but it stops there. You don't invoke a static method by using
clazz1.staticMethod()
, but usingMyClass.staticMethod()
. A static method is not bound to an object and there is hence no notion ofthis
norsuper
in a static method. A static method is a global function; as a consequence there is also no notion of polymorphism and, therefore, method overriding makes no sense.But this could be possible if
MyClass
was an object at run-time on which you invoke a method, as in Smalltalk (or maybe JRuby as one comment suggest, but I know nothing of JRuby).Oh yeah... one more thing. You can invoke a static method through an object
obj1.staticMethod()
but that really syntactic sugar forMyClass.staticMethod()
and should be avoided. It usually raises a warning in modern IDE. I don't know why they ever allowed this shortcut.方法重写是通过动态分派实现的,这意味着对象的声明类型无法确定它的行为,而是它的运行时类型:
即使
lassie
和kermit
都被声明为Animal
类型的对象,它们的行为(方法>.speak()
) 有所不同,因为动态调度只会绑定方法调用< code>.speak() 在运行时实现,而不是在编译时实现。现在,
static
关键字开始变得有意义:“静态”一词是“动态”的反义词。 这就是为什么不能重写静态方法的原因是因为静态成员没有动态调度 - 因为静态字面意思是“非动态”。如果它们动态调度(因此可以被覆盖),static
关键字就不会不再有意义了。Method overriding is made possible by dynamic dispatching, meaning that the declared type of an object doesn't determine its behavior, but rather its runtime type:
Even though both
lassie
andkermit
are declared as objects of typeAnimal
, their behavior (method.speak()
) varies because dynamic dispatching will only bind the method call.speak()
to an implementation at run time - not at compile time.Now, here's where the
static
keyword starts to make sense: the word "static" is an antonym for "dynamic". So the reason why you can't override static methods is because there is no dynamic dispatching on static members - because static literally means "not dynamic". If they dispatched dynamically (and thus could be overriden) thestatic
keyword just wouldn't make sense anymore.是的。实际上Java允许重写静态方法,理论上是不行的,如果你在Java中重写静态方法,那么它会顺利编译和运行,但它会失去Java的基本属性多态性。您会到处读到不可能尝试自己编译和运行。你会得到答案的。例如,如果您有 Animal 类和静态方法 eat() 并且您在其子类中覆盖该静态方法,则可以将其称为 Dog。然后,当您将 Dog 对象分配给 Animal Reference 并根据 Java Dog 的 eat() 调用 eat() 时,应该已调用,但在静态覆盖动物中会调用 eat() 。
根据Java的多态原理,输出应该是
Dog Eating
。但结果不同,因为为了支持多态性,Java 使用了后期绑定,这意味着方法仅在运行时调用,而静态方法则不然。在静态方法中,编译器在编译时而不是运行时调用方法,因此我们根据引用而不是根据包含引用的对象获取方法,这就是为什么您可以说实际上它支持静态覆盖,但理论上它不支持't。
Yes. Practically Java allows overriding static method, and No theoretically if you Override a static method in Java then it will compile and run smoothly but it will lose Polymorphism which is the basic property of Java. You will Read Everywhere that it is not possible to try yourself compiling and running. you will get your answer. e.g. If you Have Class Animal and a static method eat() and you Override that static method in its Subclass lets called it Dog. Then when wherever you Assign a Dog object to an Animal Reference and call eat() according to Java Dog's eat() should have been called but in static Overriding Animals' eat() will Be Called.
According to Polymorphism Principle of Java, the Output Should be
Dog Eating
.But the result was different because to support Polymorphism Java uses Late Binding that means methods are called only at the run-time but not in the case of static methods. In static methods compiler calls methods at the compile time rather than the run-time, so we get methods according to the reference and not according to the object a reference a containing that's why You can say Practically it supports static overring but theoretically, it doesn't.
在 Java(以及许多 OOP 语言,但我不能代表所有语言;有些根本没有静态)中,所有方法都有一个固定的签名 - 参数和类型。在虚拟方法中,第一个参数是隐含的:对对象本身的引用,当从对象内部调用时,编译器会自动添加
this
。静态方法没有区别 - 它们仍然具有固定的签名。但是,通过将方法声明为静态,您已明确声明编译器不得在该签名的开头包含隐含的对象参数。因此,调用此函数的任何其他代码都不得尝试将对堆栈上的对象的引用放入其中。如果确实这样做了,那么方法执行将无法工作,因为参数将位于堆栈上的错误位置(移位一位)。
由于两者之间的这种差异;虚拟方法始终具有对上下文对象的引用(即
this
),因此可以引用堆中属于该对象实例的任何内容。但对于静态方法,由于没有传递引用,因此该方法无法访问任何对象变量和方法,因为上下文未知。如果您希望 Java 更改定义,以便为每个方法(静态或虚拟)传递对象上下文,那么本质上您将只有虚拟方法。
正如有人在评论中询问的那样 - 您想要此功能的原因和目的是什么?
我不太了解Ruby,因为OP提到了这一点,我做了一些研究。我发现 Ruby 中的类确实是一种特殊的对象,可以创建(甚至是动态的)新方法。 Ruby 中的类是完整的类对象,而 Java 中则不是。这是您在使用 Java(或 C#)时必须接受的事情。这些不是动态语言,尽管 C# 添加了某些形式的动态。事实上,据我所知,Ruby 没有“静态”方法——在这种情况下,这些方法是单例类对象上的方法。然后,您可以使用新类覆盖此单例,并且前一个类对象中的方法将调用新类中定义的方法(正确吗?)。因此,如果您在原始类的上下文中调用方法,它仍然只会执行原始静态,但在派生类中调用方法,则会从父类或子类调用方法。很有趣,我可以看到其中的一些价值。这需要不同的思维模式。
由于您使用 Java 工作,因此您需要适应这种工作方式。他们为什么这样做?嗯,可能是为了根据现有的技术和理解来提高当时的性能。计算机语言在不断发展。回溯得足够远,就不存在 OOP 这样的东西。未来还会有其他新的想法。
编辑:另一条评论。既然我看到了这些差异,而且作为我自己的 Java/C# 开发人员,我可以理解为什么如果您来自 Ruby 这样的语言,那么从 Java 开发人员那里得到的答案可能会令人困惑。 Java
static
方法与 Rubyclass
方法不同。 Java 开发人员将很难理解这一点,相反,那些主要使用 Ruby/Smalltalk 等语言的开发人员也会很难理解这一点。我可以看出,Java 也使用“类方法”作为谈论静态方法的另一种方式,但 Ruby 对同一术语的使用方式有所不同,这一事实也让人非常困惑。 Java 没有 Ruby 风格的类方法(抱歉); Ruby 没有 Java 风格的静态方法,这些方法实际上只是旧的过程风格函数,如 C 中所示。顺便说一句 - 感谢您的提问!今天我学到了一些关于类方法(Ruby 风格)的新知识。
In Java (and many OOP languages, but I cannot speak for all; and some do not have static at all) all methods have a fixed signature - the parameters and types. In a virtual method, the first parameter is implied: a reference to the object itself and when called from within the object, the compiler automatically adds
this
.There is no difference for static methods - they still have a fixed signature. However, by declaring the method static you have explicitly stated that the compiler must not include the implied object parameter at the beginning of that signature. Therefore, any other code that calls this must must not attempt to put a reference to an object on the stack. If it did do that, then the method execution would not work since the parameters would be in the wrong place - shifted by one - on the stack.
Because of this difference between the two; virtual methods always have a reference to the context object (i.e.
this
) so then it is possible to reference anything within the heap that belong to that instance of the object. But with static methods, since there is no reference passed, that method cannot access any object variables and methods since the context is not known.If you wish that Java would change the definition so that a object context is passed in for every method, static or virtual, then you would in essence have only virtual methods.
As someone asked in a comment to the op - what is your reason and purpose for wanting this feature?
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.
Since you are working in Java, you will need to adjust to that way of doing things. Why they did this? Well, probably to improve performance at the time based on the technology and understanding that was available. Computer languages are constantly evolving. Go back far enough and there is no such thing as OOP. In the future, there will be other new ideas.
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 Rubyclass
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.By the way - thanks for the question! I learned something new for me today about class methods (Ruby style).
好吧...如果您从重写方法在 Java 中应如何表现的角度思考,答案是否定的。但是,如果您尝试重写静态方法,则不会收到任何编译器错误。这意味着,如果您尝试重写,Java 不会阻止您这样做;而是会阻止您这样做。但您肯定不会获得与非静态方法相同的效果。 Java 中的重写仅意味着将根据对象的运行时类型而不是其编译时类型来调用特定方法(重写静态方法就是这种情况)。好吧……你能猜到他们行为怪异的原因吗?因为它们是类方法,因此对它们的访问总是在编译时仅使用编译时类型信息来解析。使用对象引用访问它们只是 Java 设计者给予的额外自由,我们当然不应该只在他们限制它时才考虑停止这种做法:-)
示例:让我们尝试看看如果我们尝试重写静态方法会发生什么:-
输出:-
超类:静态方法内部
超类:静态方法内部
SubClass: inside staticMethod
请注意输出的第二行。如果 staticMethod 被重写,则这一行应该与第三行相同,因为我们在运行时类型的对象上调用“staticMethod()”作为“子类”而不是“超类”。这证实了静态方法始终仅使用其编译时类型信息来解析。
Well... the answer is NO if you think from the perspective of how an overriden method should behave in Java. But, you don't get any compiler error if you try to override a static method. That means, if you try to override, Java doesn't stop you doing that; but you certainly don't get the same effect as you get for non-static methods. Overriding in Java simply means that the particular method would be called based on the run time type of the object and not on the compile time type of it (which is the case with overriden static methods). Okay... any guesses for the reason why do they behave strangely? Because they are class methods and hence access to them is always resolved during compile time only using the compile time type information. 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 :-)
Example: let's try to see what happens if we try overriding a static method:-
Output:-
SuperClass: inside staticMethod
SuperClass: inside staticMethod
SubClass: inside staticMethod
Notice the second line of the output. Had the staticMethod been overriden this line should have been identical to the third line as we're invoking the 'staticMethod()' on an object of Runtime Type as 'SubClass' and not as 'SuperClass'. This confirms that the static methods are always resolved using their compile time type information only.
通过重写,您可以实现动态多态性。
当您说重写静态方法时,您尝试使用的词语是矛盾的。
静态表示-编译时,重写用于动态多态性。
两者性质相反,不能同时使用。
当程序员使用对象并访问实例方法时,就会出现动态多态行为。 JRE将根据您使用的对象类型映射不同类的不同实例方法。
当你说重写静态方法时,静态方法我们会通过类名来访问,类名会在编译时链接,所以不存在运行时与静态方法链接的概念。因此,术语“重写”静态方法本身没有任何意义。
注意:即使你用一个对象访问一个类方法,java编译器仍然有足够的智能来找到它,并且会做静态链接。
By overriding, you achieve dynamic polymorphism.
When you say overriding static methods, the words you are trying to use are contradictory.
Static says - compile time, overriding is used for dynamic polymorphism.
Both are opposite in nature, and hence can't be used together.
Dynamic polymorphic behavior comes when a programmer uses an object and accessing an instance method. JRE will map different instance methods of different classes based on what kind of object you are using.
When you say overriding static methods, static methods we will access by using the class name, which will be linked at compile time, so there is no concept of linking methods at runtime with static methods. So the term "overriding" static methods itself doesn't make any meaning.
Note: even if you access a class method with an object, still java compiler is intelligent enough to find it out, and will do static linking.
我喜欢并加倍杰伊的评论(https://stackoverflow.com/a/2223803/1517187)。
我同意这是 Java 的糟糕设计。
正如我们在之前的评论中看到的,许多其他语言支持重写静态方法。
我感觉 Jay 也和我一样从 Delphi 来到了 Java。
Delphi (Object Pascal) 是在 Java 之前实现 OOP 的语言之一,也是最早用于商业应用程序开发的语言之一。
显然,许多人都曾使用过该语言,因为它在过去是编写商业 GUI 产品的唯一语言。并且 - 是的,我们可以在 Delphi 中重写静态方法。实际上,Delphi中的静态方法被称为“类方法”,而Delphi有不同的“Delphi静态方法”概念,它是早期绑定的方法。要覆盖必须使用后期绑定的方法,请声明“virtual”指令。所以它非常方便和直观,我希望在 Java 中也能做到这一点。
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.
一般来说,允许“重写”静态方法是没有意义的,因为没有好的方法来确定在运行时调用哪个方法。以 Employee 为例,如果我们调用 RegularEmployee.getBonusMultiplier() - 应该执行哪个方法?
就 Java 而言,人们可以想象一种语言定义,只要通过对象实例调用静态方法,就可以“覆盖”静态方法。然而,这一切只是重新实现常规类方法,为语言添加冗余,而没有真正增加任何好处。
In general it doesn't make sense to allow 'overriding' of static methods as there would be no good way to determine which one to call at runtime. Taking the Employee example, if we call RegularEmployee.getBonusMultiplier() - which method is supposed to be executed?
In the case of Java, one could imagine a language definition where it is possible to 'override' static methods as long as they are called through an object instance. However, all this would do is to re-implement regular class methods, adding redundancy to the language without really adding any benefit.
重写是为实例成员保留的,以支持多态行为。静态类成员不属于特定实例。相反,静态成员属于该类,因此不支持重写,因为子类仅继承受保护和公共实例成员,而不继承静态成员。您可能想要定义接口并研究工厂和/或策略设计模式来评估替代方法。
overriding is reserved for instance members to support polymorphic behaviour. static class members do not belong to a particular instance. instead, static members belong to the class and as a result overriding is not supported because subclasses only inherit protected and public instance members and not static members. You may want to define an inerface and research factory and/or strategy design patterns to evaluate an alternate approach.
通过重写,我们可以根据对象类型创建多态性。静态方法与对象没有关系。所以java不支持静态方法重写。
By overriding we can create a polymorphic nature depending on the object type. Static method has no relation with object. So java can not support static method overriding.
Java 中的覆盖仅仅意味着将根据运行时类型调用特定方法
对象的而不是它的编译时类型(这是覆盖静态方法的情况)。由于静态方法是类方法,它们不是实例方法,因此它们与哪个引用指向哪个对象或实例这一事实无关,因为由于静态方法的性质,它属于特定的类。您可以在子类中重新声明它,但该子类不会知道有关父类静态方法的任何信息,因为正如我所说,它仅特定于声明它的类。使用对象引用访问它们只是 Java 设计者赋予的额外自由,我们当然不应该只在他们限制时才考虑停止这种做法
更多细节和示例
http://faisalbhagat.blogspot.com/2014/ 09/method-overriding-and-method-hiding.html
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
重写静态方法有什么好处。您不能通过实例调用静态方法。
编辑:看来,由于语言设计中的一个不幸的疏忽,您可以通过实例调用静态方法。一般来说没有人这样做。我的不好。
What good will it do to override static methods. You cannot call static methods through an instance.
EDIT : It appears that through an unfortunate oversight in language design, you can call static methods through an instance. Generally nobody does that. My bad.
这个问题的答案很简单,标记为static的方法或变量只属于该类,因此静态方法不能在子类中继承,因为它们只属于超类。
Answer of this question is simple, the method or variable marked as static belongs to the class only, So that static method cannot be inherited in the sub class because they belong to the super class only.
简单的解决方案:使用单例实例。它将允许覆盖和继承。
在我的系统中,我有 SingletonsRegistry 类,它返回传递的类的实例。如果没有找到实例,则创建它。
Haxe语言课程:
Easy solution: Use singleton instance. It will allow overrides and inheritance.
In my system, I have SingletonsRegistry class, which returns instance for passed Class. If instance is not found, it is created.
Haxe language class:
静态方法、变量、块或嵌套类属于整个类而不是一个对象。
Java 中的方法用于公开对象/类的行为。这里,由于方法是静态(即静态方法仅用于表示类的行为。)更改/覆盖整个类的行为将违反该现象面向对象编程的基本支柱之一,即高内聚。 (请记住,构造函数是 Java 中的一种特殊方法。)
高内聚 - 一个类应该只有一个角色。例如:汽车类应该只生成汽车对象,而不是自行车、卡车、飞机等。但是汽车类可能有一些仅属于其自身的功能(行为)。
因此,在设计java编程语言时。语言设计者认为,只有通过使方法本质上是静态的,才能允许开发人员将类的某些行为保留给自己。
下面的代码尝试重写静态方法,但不会遇到任何编译错误。
这是因为,这里我们没有重写方法,而只是重新声明它。 Java 允许重新声明方法(静态/非静态)。
从 Car 类的 getVehileNumber() 方法中删除 static 关键字将导致编译错误,因为我们试图更改仅属于 Vehicle 类的静态方法的功能。
另外,如果 getVehileNumber() 被声明为 final 那么代码将无法编译,因为 Final 关键字限制程序员重新声明该方法。
总的来说,这取决于软件设计者在哪里使用静态方法。
我个人更喜欢使用静态方法来执行某些操作,而无需创建类的任何实例。其次,向外界隐藏一个阶级的行为。
A Static method, variable, block or nested class belongs to the entire class rather than an object.
A Method in Java is used to expose the behaviour of an Object / Class. Here, as the method is static (i.e, static method is used to represent the behaviour of a class only.) changing/ overriding the behaviour of entire class will violate the phenomenon of one of the fundamental pillar of Object oriented programming i.e, high cohesion. (remember a constructor is a special kind of method in Java.)
High Cohesion - One class should have only one role. For example: A car class should produce only car objects and not bike, trucks, planes etc. But the Car class may have some features(behaviour) that belongs to itself only.
Therefore, while designing the java programming language. The language designers thought to allow developers to keep some behaviours of a class to itself only by making a method static in nature.
The below piece code tries to override the static method, but will not encounter any compilation error.
This is because, here we are not overriding a method but we are just re-declaring it. Java allows re-declaration of a method (static/non-static).
Removing the static keyword from getVehileNumber() method of Car class will result into compilation error, Since, we are trying to change the functionality of static method which belongs to Vehicle class only.
Also, If the getVehileNumber() is declared as final then the code will not compile, Since the final keyword restricts the programmer from re-declaring the method.
Overall, this is upto software designers for where to use the static methods.
I personally prefer to use static methods to perform some actions without creating any instance of a class. Secondly, to hide the behaviour of a class from outside world.
这是一个简单的解释。静态方法与类关联,而实例方法与特定对象关联。重写允许调用与特定对象关联的重写方法的不同实现。因此,重写静态方法是违反直觉的,因为静态方法甚至不与对象关联,而是首先与类本身关联。因此,静态方法不能根据调用它的对象来重写,它将始终与创建它的类相关联。
Here is a simple explanation. A static method is associated with a class while an instance method is associated with a particular object. Overrides allow calling the different implementation of the overridden methods associated with the particular object. So it is counter-intuitive to override static method which is not even associated with objects but the class itself in the first place. So static methods cannot be overridden based on what object is calling it, it will always be associated with the class where it was created.
现在看到上面的答案每个人都知道我们不能重写静态方法,但是人们不应该误解从子类访问静态方法的概念。
例如,请参见下面的代码:-
输出:-
谢谢
Now seeing above answers everyone knows that we can't override static methods, but one should not misunderstood about the concept of accessing static methods from subclass.
For Example, see below code:-
Output:-
Thanks
下面的代码表明这是可能的:
The following code shows that it is possible: