繁体   English   中英

为什么静态方法不涉及多态(后期绑定)我看到错误,静态方法不能被覆盖

[英]Why if static method don't involve in polymorphism(late binding) I see error that static method cannot be overridden

请考虑以下代码:

class A{
    public static void m(Number n){
         System.out.println("Number A");
    };
}
class B extends A{
     public static int m(Number n){
        System.out.println("Number B");
        return 1;
      };
}

输出:

java中的:inheritanceTest.B中的m(java.lang.Number)不能覆盖inheritanceTest中的m(java.lang.Number)。返回类型int与void不兼容

我知道静态方法不涉及多态,因此我推断我的代码不可能覆盖。 这个编译器消息对我来说很奇怪。

据我所知,重写是多态的一部分。 我准备scjp,我害怕在熟悉的问题上犯错误。

请澄清这个问题。

我的预期行为 - 有关重载错误的消息

P.S1。

我已经阅读了关于静态覆盖的最受欢迎的问题,我没有找到答案(

P.S2。 据Pshemo回答:

这段代码:

class Foo{
    public static void m(Number n){
         System.out.println("Number A");
    };
    public static int m(Number n){
        System.out.println("Number B");
        return 1;
    };
}

输出:

error: method m(Number) is already defined in class Foo
    public static int m(Number n){
                      ^
1 error

对我来说,这些情况是一样的。 但编译器错误不同 - 很奇怪。

即使静态方法无法被覆盖,它们仍然是继承的,所以你要做的事情会导致类似的情况

class Foo{
    public static void m(Number n){
         System.out.println("Number A");
    };
    public static int m(Number n){
        System.out.println("Number B");
        return 1;
    };
}

这是错误的,因为你不能有两个具有相同签名但具有不同返回类型的方法。 它被禁止的原因很简单......让我们说我们有方法:

  • Foo method(){ return new Foo(); }
  • Bar method(){ return new Bar(); }

你会想要像他们一样调用它们

System.out.println(method());

结果应该是Foo还是Bar? 编译器无法决定。

为了防止这种情况,编译器通过更改其返回类型来禁止覆盖/隐藏具有相同签名的方法。 唯一的例外是当您将返回类型更改为更详细的类型时

class X{
    List<String> m(){...}
}

class Y extends X{
    LinkedList<String> m(){...}
}

因此, override似乎不是最好的词。 应该hide正确的单词,因为静态方法可以隐藏,而不是被覆盖。 但它看起来像是相同的规则(或至少它们的一部分)用于测试我们是否可以将方法隐藏为覆盖规则,因此在出现问题时会显示相同的错误消息(关于覆盖而不是隐藏),这可能是误导。

JLS§8.4.8.3(Java 8)说:

如果一个方法声明d 1与返回类型的R 1所 覆盖或隐藏的另一方法d 2与返回类型中的R 2的声明,则d 1必须返回型取代(§8.4.5)为d 2,或编译发生时间错误。

同样的规则同时适用于实例方法和静态方法,因为它表示“覆盖或隐藏”。 基本上,如果你有一个具有相同名称和相同参数的方法,它会覆盖它是一个实例方法,但如果它是一个类(静态)方法则隐藏(继承方法)。 在这两种情况下,返回类型必须相同或遵守协方差规则。

由于它是相同的规则,很可能在编译器代码中只有一个地方检查此规则,如果规则被违反,您将收到您正在看到的错误,我确信这是更常见的情况。 编译器确实应该检查是否应该说“覆盖”或“隐藏”,但看起来它们会滑落。 完全正确地获取错误消息通常不是编译器编写者的最高优先级 - 与确保编译应该编译的代码并运行正确,而不应该编译的代码不相比。 所以我认为这是一个缺陷,但非常小。

我认为'覆盖'的编译器错误用法在这里有误导性,它不适用。

语言规范说:

如果具有返回类型R1的方法声明d1覆盖或隐藏具有返回类型R2的另一个方法d2的声明,则d1必须是d2的return-type substitutable,否则会发生编译时错误。

这里你的B方法隐藏了Am的声明:

如果一个类声明了静态方法m,则声明m被称为隐藏任何方法m',其中m的签名是m'签名的子签名(第8.4.2节),在超类和超接口中。该类中的代码可以访问的类。

如果你的B类没有m方法,那么你可以调用Bm,它会调用A上定义的m。

让Bm隐藏A的m版本。 因为您可以调用在超类上定义的静态方法但引用子类,这会设置对不同返回类型违反的方法的一些期望。

它隐藏而不是覆盖,因为如果你定义了Bm,你仍然可以调用Am并获得该方法的超类版本。 覆盖它的运行时类型决定了被调用的内容以及它的调用方式并不重要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM