最终静态方法的行为

Har*_*ish 117 java methods static final

我一直在玩静态方法的修饰符,并遇到了一个奇怪的行为.

我们知道,静态方法不能被覆盖,因为它们与类而不是实例相关联.

所以,如果我有下面的代码片段,它编译得很好

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如果我在A类中将final修饰符包含到静态方法中,则编译失败 ,B中的ts()不能覆盖A中的ts(); 重写方法是静态最终的.

当静态方法根本无法被覆盖时,为什么会发生这种情况?

Naw*_*Man 157

静态方法不能被覆盖,但可以隐藏它们.ts()B 的方法不是覆盖(不受多态性)的ts()A,但它会隐藏它.如果调用ts()在B(NOT A.ts()B.ts()...只是ts()),B的一个将被调用,而不是A.因为这不会受到多态性,该呼叫ts()在一个永远不会被重定向到一个在B.

该关键字final将禁止隐藏该方法.因此它们无法隐藏,尝试这样做会导致编译器错误.

希望这可以帮助.

  • 或许完成你的答案,我相信这是正确的,这里的问题基本上是一个糟糕的编译错误信息:它应该说B不能*隐藏*ts()在A中.声明一个静态方法final声明它无法隐藏. (30认同)
  • @Sean Owen:我也这么认为.术语"隐藏"甚至在Java规范中使用,因此为什么不在编译器消息中使用它. (2认同)
  • 为什么这甚至是一个功能?它在什么情况下有用? (2认同)

Vin*_*nie 12

静态方法无法覆盖

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

  • 这是不正确的.静态方法不能被覆盖,但如果您在实例引用而不是类名称上调用它们,则可以隐藏它们. (4认同)

Pow*_*ord 10

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

A.ts()并且B.ts()总是分开的方法.

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

您会认为错误消息将使用隐藏字而不是覆盖...


Mat*_*der 5

考虑到以下因素,您可能会发现自己可以考虑制作静态方法.

有以下课程:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}
Run Code Online (Sandbox Code Playgroud)

现在调用这些方法的"正确"方法是

A.ts();
B.ts();
Run Code Online (Sandbox Code Playgroud)

这会产生AB但你也可以在实例上调用方法:

A a = new A();
a.ts();
B b = new B();
b.ts();
Run Code Online (Sandbox Code Playgroud)

这也会导致AB.

现在考虑以下内容:

A a = new B();
a.ts();
Run Code Online (Sandbox Code Playgroud)

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

A a = new B();
((B)a).ts();
Run Code Online (Sandbox Code Playgroud)

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

现在假设您是类的开发人员,A并且您希望允许子类.但是你真的想要方法ts(),无论什么时候被调用,甚至是从子类,这是你希望它做的事情,而不是被子类版本隐藏.然后你可以制作它final并防止它隐藏在子类中.并且您可以确保以下代码将从您的类中调用该方法A:

B b = new B();
b.ts();
Run Code Online (Sandbox Code Playgroud)

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

您不应该在实例上调用静态方法,而是直接在类上调用 - 那么您就不会遇到这个问题.例如,IntelliJ IDEA会向您显示警告,如果您在实例上调用静态方法,并且如果您将静态方法调用为final.