最终静态方法的行为

发布于 2024-08-11 07:08:17 字数 389 浏览 12 评论 0原文

我一直在尝试使用静态方法的修饰符,并遇到了一个奇怪的行为。

众所周知,静态方法不能被重写,因为它们与类而不是实例相关联。

因此,如果我有下面的代码片段,它可以正常编译

//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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

月下伊人醉 2024-08-18 07:08:17

静态方法不能被重写,但可以隐藏。 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) the ts() of A but it will hide it. If you call ts() in B (NOT A.ts() or B.ts() ... just ts()), the one of B will be called and not A. Since this is not subjected to polymorphism, the call ts() 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.

万劫不复 2024-08-18 07:08:17

静态方法不能被重写

这并不完全正确。示例代码实际上意味着 B 中的方法 ts 隐藏了 A 中的方法 ts。因此它并不完全覆盖。在 Javaranch 上有一个很好的解释。

static methods cannot be overriden

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.

不醒的梦 2024-08-18 07:08:17

静态方法属于类,而不属于实例。

A.ts()B.ts() 始终是单独的方法。

真正的问题是 Java 允许您在实例对象上调用静态方法。与父类具有相同签名的静态方法是隐藏的 当从子类的实例调用时。但是,您无法覆盖/隐藏 final 方法

您可能会认为错误消息会使用“隐藏”一词而不是“覆盖”......

Static methods belong to the class, not the instance.

A.ts() and B.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...

镜花水月 2024-08-18 07:08:17

您可能会发现自己正在考虑将静态方法设为 Final,考虑以下因素:

拥有以下类:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

现在调用这些方法的“正确”方法将是

A.ts();
B.ts();

导致 AB 但您还可以调用实例上的方法:

A a = new A();
a.ts();
B b = new B();
b.ts();

这也会导致 AB

现在考虑以下情况:

A a = new B();
a.ts();

这将打印 A。这可能会让您感到惊讶,因为您实际上拥有一个 B 类的对象。但由于您是从 A 类型的引用调用它,因此它将调用 A.ts()。您可以使用以下代码打印 B

A a = new B();
((B)a).ts();

在这两种情况下,您拥有的对象实际上来自类 B。但根据指向对象的指针,您将从 AB 调用方法。

现在假设您是类 A 的开发人员,并且您希望允许子类化。但是您确实想要方法ts(),无论何时调用,即使是从子类调用,它都会执行您希望它执行的操作,而不是被子类版本隐藏。然后您可以将其设为final并防止其隐藏在子类中。并且您可以确定以下代码将调用您的类 A 中的方法:

B b = new B();
b.ts();

好吧,承认这是以某种方式构造的,但对于某些情况可能是有意义的。

您不应该在实例上调用静态方法,而应该直接在类上调用静态方法 - 那么您就不会有这个问题。例如,如果您在实例上调用静态方法以及将静态方法设置为最终方法,IntelliJ IDEA 也会向您显示警告。

You might find yourself in the position to think about making a static method final, considering the following:

Having the following classes:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

Now the 'correct' way to call these methods would be

A.ts();
B.ts();

which would result in AB but you could also call the methods on instances:

A a = new A();
a.ts();
B b = new B();
b.ts();

which would result in AB as well.

Now consider the following:

A a = new B();
a.ts();

that would print A. That might surprise you since you are actually having an object of class B. But since you're calling it from a reference of type A, it will call A.ts(). You could print B with the following code:

A a = new B();
((B)a).ts();

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 from A or from B.

Now let's say you are the developer of class A and you want to allow sub-classing. But you really want method ts(), 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 it final and prevent it from being hidden in the subclass. And you can be sure that the following code will call the method from your class A:

B b = new B();
b.ts();

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.

懷念過去 2024-08-18 07:08:17

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.

冰雪梦之恋 2024-08-18 07:08:17

我认为这里的编译错误非常具有误导性。它不应该说“重写的方法是静态最终的。”,而应该说“重写的方法是最终的。”。 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.

奈何桥上唱咆哮 2024-08-18 07:08:17

与非静态方法不同,静态方法在 Java 中不能被重写。
但它们像静态和非静态数据成员一样被继承。这就是为什么不能在父类中创建同名的非静态方法。

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

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

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

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.

提笔书几行 2024-08-18 07:08:17

静态方法“隐藏”在继承类中,并且不能“非静态”地重写,即它们不能在“多态性”意义上被重写。但它们可以被“静态”覆盖。

即使“静态”,也不允许重写静态最终方法。

以下示例说明了这一点 -

App.java -

public class App {
    public static void main(String[] args) {
        Base.fun1();
        Base.fun2();
        Derived1.fun1();
        Derived1.fun2();
        Derived2.fun1();
        Derived2.fun2();
    }
}

Base.java -

public abstract class Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Base");
    }

    protected static final void fun2() {
        System.out.println("Static final fun2() called in Base");
    }

}

Derived1.java -

public class Derived1 extends Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Derived1");
    }
    
    //Not allowed to override final method
    /*
    protected static final void fun2() {
        System.out.println("Static final fun2() called in Derived1");
    }
    */
}

Derived2.java -

public class Derived2 extends Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Derived2");
    }
    
    //Not allowed to override final method
    /*
    protected static final void fun2() {
        System.out.println("Static final fun2() called in Derived2");
    }
    */
}

输出 -

Static fun1() called in Base
Static final fun2() called in Base
Static fun1() called in Derived1
Static final fun2() called in Base
Static fun1() called in Derived2
Static final fun2() called in Base

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 -

public class App {
    public static void main(String[] args) {
        Base.fun1();
        Base.fun2();
        Derived1.fun1();
        Derived1.fun2();
        Derived2.fun1();
        Derived2.fun2();
    }
}

Base.java -

public abstract class Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Base");
    }

    protected static final void fun2() {
        System.out.println("Static final fun2() called in Base");
    }

}

Derived1.java -

public class Derived1 extends Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Derived1");
    }
    
    //Not allowed to override final method
    /*
    protected static final void fun2() {
        System.out.println("Static final fun2() called in Derived1");
    }
    */
}

Derived2.java -

public class Derived2 extends Base {

    protected static void fun1() {
        System.out.println("Static fun1() called in Derived2");
    }
    
    //Not allowed to override final method
    /*
    protected static final void fun2() {
        System.out.println("Static final fun2() called in Derived2");
    }
    */
}

Output -

Static fun1() called in Base
Static final fun2() called in Base
Static fun1() called in Derived1
Static final fun2() called in Base
Static fun1() called in Derived2
Static final fun2() called in Base
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文