【问题标题】:Behaviour of final static method最终静态方法的行为
【发布时间】:2010-12-17 03:42:34
【问题描述】:

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

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

所以如果我有下面的sn-p,它编译得很好

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

class B extends A {
    static void ts() {
    }
}

但是如果我在 A 类的静态方法中包含 final 修饰符,那么编译会失败 B 中的 ts() 不能覆盖 A 中的 ts();被覆盖的方法是静态的 final

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

【问题讨论】:

  • 看起来很奇怪,为这个问题+1,但到目前为止,没有一个答案是令人满意的。
  • 它没有被覆盖。它仍然存在于 A.ts()。

标签: java methods static final


【解决方案1】:

静态方法不能被覆盖

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

【讨论】:

  • 这是真的,只是不准确。静态方法不能被覆盖,但如果您在实例引用而不是类名上调用它们,则可以隐藏它们。
  • 很遗憾,您的链接已失效。有可能解决这个问题吗?
  • javaranch 链接不起作用,但谷歌搜索关键字在代码牧场上出现this link
  • 我已编辑帖子,将死链接替换为 Sundeep 发布的链接。
【解决方案2】:

与非静态方法不同,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关键字限制了子类中同名方法的创建。

【讨论】:

  • "但是它们像静态和非静态数据成员一样被继承。"我不这么认为。它们可以从子类访问,但这与继承不同。 “final 关键字限制在子类中创建同名方法。”也不正确。您可以在子类中重载静态最终方法。您只是无法创建具有相同签名的方法。
【解决方案3】:

您可能会发现自己可以考虑将静态方法设为 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();

好的,诚然这是某种构造,但在某些情况下可能有意义。

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

【讨论】:

    【解决方案4】:

    静态方法不能被覆盖,但可以隐藏。 B 的ts() 方法不会覆盖(不受多态性影响)A 的ts(),但它会隐藏它。如果您在 B 中调用 ts()(不是 A.ts()B.ts() ... 只是 ts()),则将调用 B 而不是 A。由于这不受多态性的影响,因此调用 ts() A 中的内容永远不会被重定向到 B 中的内容。

    关键字final 将禁止隐藏该方法。所以它们不能被隐藏,尝试这样做会导致编译器错误。

    希望这会有所帮助。

    【讨论】:

    • 也许要完成你的答案,我相信这是正确的,这里的问题基本上是一个错误的编译器错误消息:它应该说 B 不能 hide ts() in A。声明一个静态方法 final 就是声明它不能被隐藏。
    • @Sean Owen:我也这么认为。术语“隐藏”甚至在 Java 规范中使用,所以为什么不在编译器消息中使用它。
    • 为什么这甚至是一个功能?在什么情况下会有用?
    • public class Test { final static public void main(String... srik) { System.out.println("In main method"); ts(); } 公共静态无效 ts() { 孩子 c=new Child(); c.ts(); System.out.println("测试 ts"); } } 公共类子扩展测试 { public static void ts() { System.out.println("Child ts"); } } 嗨,你能解释一下在这种情况下会发生什么
    • 我的书“java 如何编程第 10 版”说静态方法是隐式最终的(第 10.7 章)。 prntscr.com/u3too3 如果静态方法是最终的,如果最终方法不能隐藏。这意味着静态方法也不应该被隐藏。但是我们可以隐藏静态方法。
    【解决方案5】:

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

    A.ts()B.ts() 始终是不同的方法。

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

    你会认为错误消息会使用隐藏而不是覆盖这个词...

    【讨论】:

      【解决方案6】:

      我认为这里的编译错误非常具有误导性。它不应该说“被覆盖的方法是静态的。”,而应该说“被覆盖的方法是最终的。”。 static 修饰符在这里无关紧要。

      【讨论】:

      • 所以你认为 B 中的静态方法会覆盖 A 中的静态方法?
      • @KorayTugay 我只是想知道编译器是否首先查看 potentially 可覆盖的方法(暂时忽略静态),最终看到失败。只是一个疯狂的猜测
      • Balus 我认为这是您在 StackOverflow 中获得的唯一低质量答案。考虑到你所有的特殊答案,这个不属于他们。 @BalusC
      • @KorayTugay:当时我还没有足够的声望来发表评论:)如果你回复我,我会删除答案,没问题。
      【解决方案7】:

      B 中的 ts() 方法并没有覆盖 A 中的 ts() 方法,它只是另一种方法。 B 类看不到 A 中的 ts() 方法,因为它是静态的,因此它可以声明自己的称为 ts() 的方法。

      但是,如果方法是最终的,那么编译器会发现 A 中有一个 ts() 方法不应该在 B 中被覆盖。

      【讨论】:

      • 我认为这不能解释为什么“最终”突然意味着这些方法不能共存。正如您所说,没有“最终”,就没有问题。你说它不是覆盖,然后说问题是B不能覆盖A的方法。
      • 当然可以,我声明 B 在 A 中看不到 ts() 方法(它是“隐藏的”),但最终修饰符不会“隐藏”扩展另一个类的方法.但是,嗯,好的。
      • 我认为也许你的措辞“不应该在 B 中被覆盖”可以更改为“不应该隐藏在 B 中”
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-14
      • 2021-05-10
      • 1970-01-01
      • 2012-01-06
      相关资源
      最近更新 更多