最终静态方法的行为
我一直在尝试使用静态方法的修饰符,并遇到了一个奇怪的行为。
众所周知,静态方法不能被重写,因为它们与类而不是实例相关联。
因此,如果我有下面的代码片段,它可以正常编译
//Snippet 1 - Compiles fine
public class A {
static void ts() {
}
}
class B extends A {
static void ts() {
}
}
但是如果我在类 A 中的静态方法中包含最终修饰符,则编译失败 B 中的 ts() 不能覆盖 A 中的 ts();重写的方法是静态最终的。
当静态方法根本无法被重写时,为什么会发生这种情况?
I have been playing around with modifiers with static method and came across a weird behaviour.
As we know, static methods cannot be overridden, as they are associated with class rather than instance.
So if I have the below snippet, it compiles fine
//Snippet 1 - Compiles fine
public class A {
static void ts() {
}
}
class B extends A {
static void ts() {
}
}
But if I include final modifier to static method in class A, then compilation fails
ts() in B cannot override ts() in A; overridden method is static final.
Why is this happening when static method cannot be overridden at all?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
静态方法不能被重写,但可以隐藏。 B 的 ts() 方法不会覆盖(不受多态性影响)A 的 ts() 方法,但会隐藏它。如果您在 B 中调用
ts()
(不是A.ts()
或B.ts()
... 只是ts ()
),B 中的函数将被调用,而 A 中的函数不会被调用。由于这不受多态性的影响,因此 A 中的调用ts()
永远不会被重定向到 B 中的函数关键字final
将禁止该方法被隐藏。因此它们无法隐藏,尝试这样做将导致编译器错误。Static methods cannot be overridden but they can be hidden. The
ts()
method of B is not overriding(not subject to polymorphism) thets()
of A but it will hide it. If you callts()
in B (NOTA.ts()
orB.ts()
... justts()
), the one of B will be called and not A. Since this is not subjected to polymorphism, the callts()
in A will never be redirected to the one in B.The keyword
final
will disable the method from being hidden. So they cannot be hidden and an attempt to do so will result in a compiler error.这并不完全正确。示例代码实际上意味着 B 中的方法 ts 隐藏了 A 中的方法 ts。因此它并不完全覆盖。在 Javaranch 上有一个很好的解释。
This is not exactly true. The example code really means that the method ts in B hides the method ts in A. So its not exactly overriding. Over on Javaranch there is a nice explanation.
静态方法属于类,而不属于实例。
A.ts()
和B.ts()
始终是单独的方法。真正的问题是 Java 允许您在实例对象上调用静态方法。与父类具有相同签名的静态方法是隐藏的 当从子类的实例调用时。但是,您无法覆盖/隐藏 final 方法 。
您可能会认为错误消息会使用“隐藏”一词而不是“覆盖”......
Static methods belong to the class, not the instance.
A.ts()
andB.ts()
are always going to be separate methods.The real problem is that Java lets you call static methods on an instance object. Static methods with the same signature from the parent class are hidden when called from an instance of the subclass. However, you can't override/hide final methods.
You would think the error message would use the word hidden instead of overridden...
您可能会发现自己正在考虑将静态方法设为 Final,考虑以下因素:
拥有以下类:
现在调用这些方法的“正确”方法将是
导致
AB
但您还可以调用实例上的方法:这也会导致
AB
。现在考虑以下情况:
这将打印
A
。这可能会让您感到惊讶,因为您实际上拥有一个B
类的对象。但由于您是从A
类型的引用调用它,因此它将调用A.ts()
。您可以使用以下代码打印B
:在这两种情况下,您拥有的对象实际上来自类
B
。但根据指向对象的指针,您将从A
或B
调用方法。现在假设您是类
A
的开发人员,并且您希望允许子类化。但是您确实想要方法ts()
,无论何时调用,即使是从子类调用,它都会执行您希望它执行的操作,而不是被子类版本隐藏。然后您可以将其设为final
并防止其隐藏在子类中。并且您可以确定以下代码将调用您的类A
中的方法:好吧,承认这是以某种方式构造的,但对于某些情况可能是有意义的。
您不应该在实例上调用静态方法,而应该直接在类上调用静态方法 - 那么您就不会有这个问题。例如,如果您在实例上调用静态方法以及将静态方法设置为最终方法,IntelliJ IDEA 也会向您显示警告。
You might find yourself in the position to think about making a static method final, considering the following:
Having the following classes:
Now the 'correct' way to call these methods would be
which would result in
AB
but you could also call the methods on instances:which would result in
AB
as well.Now consider the following:
that would print
A
. That might surprise you since you are actually having an object of classB
. But since you're calling it from a reference of typeA
, it will callA.ts()
. You could printB
with the following code:In both cases the object you have is actually from class
B
. But depending on the pointer that points to the object, you will call method fromA
or fromB
.Now let's say you are the developer of class
A
and you want to allow sub-classing. But you really want methodts()
, whenever called, even from a subclass, that is does what you want it to do and not to be hidden by a subclass version. Then you could make itfinal
and prevent it from being hidden in the subclass. And you can be sure that the following code will call the method from your classA
:Ok, admittetly that is somehow constructed, but it might make sense for some cases.
You should not call static methods on instances but directly on the classes - then you won't have that problem. Also IntelliJ IDEA for example will show you a warning, if you call a static method on an instance and as well if you make a static method final.
B 中的 ts() 方法不会覆盖 A 中的 ts() 方法,它只是另一个方法。 B 类看不到 A 中的 ts() 方法,因为它是静态的,因此它可以声明自己的方法,称为 ts()。
但是,如果该方法是最终方法,则编译器将发现 A 中有一个不应在 B 中重写的 ts() 方法。
The ts() method in B is not overriding the ts() method in A, it simply is another method. The B class does not see the ts() method in A since it is static, therefore it can declare its own method called ts().
However, if the method is final, then the compiler will pick up that there is a ts() method in A that should not be overridden in B.
我认为这里的编译错误非常具有误导性。它不应该说“重写的方法是静态最终的。”,而应该说“重写的方法是最终的。”。 static 修饰符在这里无关紧要。
I think the compilation error was quite misleading here. It should not have said "overridden method is static final.", but it should instead have said "overridden method is final.". The static modifier is irrelevant here.
与非静态方法不同,静态方法在 Java 中不能被重写。
但它们像静态和非静态数据成员一样被继承。这就是为什么不能在父类中创建同名的非静态方法。
final
关键字确保每次调用该方法时都会运行特定的方法体。现在,如果在子类中创建同名的静态方法并调用该方法,则子类中的方法将被执行,但如果父类中的静态方法名称之前带有final前缀,则不应该出现这种情况。因此final关键字限制了子类中同名方法的创建。
A static method can't be overridden in Java, unlike non-static methods.
But they are inherited like static and non-static data members. That is why a non-static method with the same name can't be created in the parent class
The
final
keyword ensures that the specific method body be run everytime a call to the method.Now if a static method is created in the child class with the same name and a call to the method is made, the method in the subclass gets executed which should not be the case if final is prefixed before the static method name in the parent class. Hence final keyword restricts the creation of method with the same name in the child class.
静态方法“隐藏”在继承类中,并且不能“非静态”地重写,即它们不能在“多态性”意义上被重写。但它们可以被“静态”覆盖。
即使“静态”,也不允许重写静态最终方法。
以下示例说明了这一点 -
App.java
-Base.java
-Derived1.java
-Derived2.java
-输出 -
Static methods are "hidden" in inherited classes and cannot be overridden "non-statically" i.e. they cannot be overridden in a "polymorphism" sense. But they can be overridden "statically".
Static final methods are not allowed to be overridden even "statically".
The following example illustrates this -
App.java
-Base.java
-Derived1.java
-Derived2.java
-Output -