【问题标题】:Why doesn't the compiler complain when I try to override a static method?为什么当我尝试覆盖静态方法时编译器不抱怨?
【发布时间】:2013-05-13 02:46:29
【问题描述】:

我知道我们不能覆盖 Java 中的静态方法,但是有人可以解释以下代码吗?

class A {
    public static void a() { 
        System.out.println("A.a()");
    }
}   

class B extends A {
    public static void a() {
        System.out.println("B.a()");
    }
}

我如何能够覆盖 B 类中的方法 a()

【问题讨论】:

  • 因为你没有。 B.a() 只能通过类 B 访问。如果你有类似A a = new B(); a.a(); 的东西,它会打印“A.a()”,即使它是 B 类型。如果它真的被覆盖,那么它会打印“B.a()”。请注意,Java 的奇怪特性是允许您从对象实例调用静态方法,这有助于在此造成混乱。
  • 是什么让您认为您在 B 中覆盖了 a?您可以通过在该方法之前添加 @Override 注释来轻松测试。
  • 如果您从B 中删除a() 函数,您可以测试a() 是否被B 继承。它确实继承,但不会覆盖。相反,如果您在 B 中声明另一个 a() 函数,它会隐藏 a()
  • @Dorus dlev 现在明白了。谢谢你。

标签: java static-methods overriding


【解决方案1】:

static 方法没有被继承,因此它的 B 方法的单独副本

staticclass 相关,而不是Object 的状态

【讨论】:

  • 这是错误的,您确实继承了静态方法,但是在子类中声明具有相同签名的另一个方法的机制称为隐藏,其工作方式与覆盖略有不同。
  • 你如何继承静态方法@Dorus?
  • +1 for @Dorus... 静态方法不会像他在上一条评论中显示的那样被继承。
【解决方案2】:

您没有覆盖方法a(),因为static 方法没有被继承。如果你输入了@Override,你会看到一个错误。

A.java:10: error: method does not override or implement a method from a supertype
    @Override
    ^
1 error

但这并不妨碍您在两个类中定义具有相同签名的静态方法。

【讨论】:

    【解决方案3】:

    你没有在这里覆盖任何东西。要自己查看,请尝试在 B 类中将 @Override 注释放在 public static void a() 之前,Java 会抛出错误。

    您刚刚在类B 中定义了一个名为a() 的函数,它与类A 中的函数a() 不同(没有任何关系)。

    但是因为B.a()与父类中的函数同名,它隐藏 A.a() [正如Eng.福阿德]。在运行时,编译器使用声明引用的实际类来确定运行哪个方法。例如,

    B b = new B();
    b.a() //prints B.a()
    
    A a = (A)b;
    a.a() //print A.a(). Uses the declared reference's class to find the method.
    

    您不能覆盖 Java 中的静态方法。请记住static 方法和字段与类相关联,而不是与对象相关联。 (尽管在 Smalltalk 等某些语言中,这是可能的)。

    我在这里找到了一些好的答案:Why doesn't Java allow overriding of static methods?

    【讨论】:

    • 您声称静态方法不是继承的,但如果我从B 中删除a(),那么B.a(); 会突然打印“A.a()”。您确实继承了静态方法,但您不会覆盖它们。相反,您将它们隐藏起来,就像 Eng.Fouad 在他的回答中提到的那样。
    • @Dorus 没有看到任何地方提到的继承!
    • 确实没有提到继承,但是在编辑之前这个答案使它看起来像静态方法,没有继承,或者至少不完整。
    【解决方案4】:

    这就是hiding a method,如Java教程Overriding and Hiding Methods中所述:

    如果一个子类定义了一个具有相同签名的类方法 超类中的类方法,子类中的方法隐藏 超类中的一个。

    【讨论】:

    • hmmm...不确定这是否是方法隐藏。 AB 都有 static a() 并且根据声明的引用类型,编译器将找到并调用正确的函数。例如。 A a = new B(); a.a(); //prints A.a() since the compiler looks at the declared reference of a which is A
    • @goblinjuice 在B 中声明a() 会将Aa() 隐藏在B 中。
    • @goblinjuice 这是Java中隐藏的字面定义
    【解决方案5】:

    另外,调用方法的选择取决于变量的声明的类型。

    B b = null;
    b.a(); // (1) prints B.a()
    A a = new B();
    a.a(); // (2) prints a.a() 
    

    在(1)处,如果系统关心b 的身份,它会抛出NPE。在 (2) 处,a 的值被忽略。由于a 被声明为A,因此会调用A.a()

    【讨论】:

    • 但是,您不应该在类实例上调用静态方法。
    • 是的。但这是展示这种特殊行为的方式。 “你可以在 null 上调用方法吗?真的吗?”
    【解决方案6】:

    您的方法不是被覆盖的方法。您只需尝试将 @Override 注释放在派生类中的方法之前。它会给你一个编译时错误。所以java不允许你覆盖静态方法。

    【讨论】:

      【解决方案7】:

      静态方法将通过其类名调用,因此我们不需要创建类对象,我们只需使用类名调用它,因此我们不能覆盖静态

      例如

      class AClass{
      public static void test(){
      
       } 
      }
      
      class BClass extends AClass{
      public static void test(){}
      
      }
      
      class CClass extends BClass{
      public static void main(String args[]){
      
      AClass aclass=new AClass();
      
      aclass.test(); // its wrong because static method is called 
                     // by its class name it can't accept object
      }
      }
      

      我们就这么称呼它

      AClass.test();

      表示静态类不能被覆盖 如果它被覆盖,那么如何调用它。

      【讨论】:

        【解决方案8】:

        虽然 goblinjuice 的答案被接受了,但我认为示例代码可以改进:

        public class StaticTest {
            public static void main(String[] args) {
                A.print();
                B.print();
                System.out.println("-");
        
                A a = new A();
                B b = new B();
                a.print();
                b.print();
                System.out.println("-");
        
                A c = b;
                c.print();
            }
        }
        
        class A {
            public static void print() {
                System.out.println("A");
            }
        }
        
        class B extends A {
            public static void print() {
                System.out.println("B");
            }
        }
        

        生产:

        A
        B
        -
        A
        B
        -
        A
        

        如果 B 已覆盖 print(),它将在最后一行写入 B。

        【讨论】:

          【解决方案9】:

          静态成员属于类而不属于任何对象。因此静态方法不能被覆盖。在运行时也会发生覆盖,因此编译器不会抱怨。

          不过,您可以在方法中添加@Override 注解。这将标记编译器错误。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-03-28
            • 2016-11-01
            • 2012-06-19
            • 2020-01-14
            • 2012-05-21
            • 2012-09-12
            相关资源
            最近更新 更多