如果静态方法不能被覆盖,它在这里是如何工作的(For Java)?

If static methods can't be overridden, how its working here (For Java)?

我的理解是静态变量和静态方法属于class,而不是class objects。因此静态方法的 Override 在 Java 中不起作用,至于覆盖我们需要创建一个 class 的实例。但我今天正在尝试一些与我对 Java.

的知识相矛盾的事情

请遵循此代码:

class Parent{
   public static void doIt(){
      System.out.println("In static method 'doit' of class Parent ");
   }
}

class Child extends Parent{    
   public static void doIt(){
      System.out.println("In static method 'doit' of class Child ");
   }
}

public class StaticPractise{
   public static void main(String[] args){
      Parent.doIt();
      Child.doIt();
   }    
}

以上实现的输出为:

D:\Rahul Shivsharan\MyPractise\JAVA>java StaticPractise
In static method 'doit' of class Parent
In static method 'doit' of class Child

从这个输出我可以了解到,虽然 Child class 扩展了 Parent class,但 doit 方法对于每个 class 因为它们是 static。所以不允许覆盖它们。

现在请按照下面的代码,其中 @Override 添加到 child 的 doIt 方法中:

class Parent{
   public static void doIt(){
      System.out.println("In static method 'doit' of class Parent ");
   }
}

class Child extends Parent{    
   @Override // Adding this annotation here
   public static void doIt(){
      System.out.println("In static method 'doit' of class Child ");
   }
}

public class StaticPractise{
   public static void main(String[] args){
      Parent.doIt();
      Child.doIt();
   }    
}

以上代码的输出给出如下编译错误:

D:\Rahul Shivsharan\MyPractise\JAVA>javac StaticPractise.java
StaticPractise.java:31: error: method does not override or implement a method from a supertype
    @Override
    ^
1 error

这里明确指出注释 Override 不能应用于 static 方法,因为它们不会被覆盖。

现在请按照下面的代码,其中 Child 没有 doIt 方法:

class Parent{
   public static void doIt(){
      System.out.println("In static method 'doit' of class Parent ");
   }
}

class Child extends Parent{ /* no doIt method */ }

public class StaticPractise{
   public static void main(String[] args){
      Parent.doIt();
      Child.doIt();
   }    
}

输出为:

D:\Rahul Shivsharan\MyPractise\JAVA>java StaticPractise
In static method 'doit' of class Parent
In static method 'doit' of class Parent

为什么上面的代码可以编译运行?我期待 class Child 的方法 doit 的编译错误,我期待 "Method not found"。没看懂。

也请按照下面的代码。这里,Parent 中的 doIt 方法现在是 final.

class Parent{
   public static final void doIt(){ // now final
      System.out.println("In static method 'doit' of class Parent ");
   }
}

class Child extends Parent{
   public static void doIt(){
      System.out.println("In static method 'doit' of class Parent ");
   }
}

public class StaticPractise{
   public static void main(String[] args){
      Parent.doIt();
      Child.doIt();
   }    
}

以上代码运行后输出如下:

D:\Rahul Shivsharan\MyPractise\JAVA>javac StaticPractise.java
StaticPractise.java:30: error: doIt() in Child cannot override doIt() in Parent
    public static void doIt(){
                       ^
  overridden method is static,final
 1 error

 D:\Rahul Shivsharan\MyPractise\JAVA>

我所期望的是上面的代码应该可以正常工作,因为 doit 方法在每个 class 中都是静态的,所以即使是 final 关键字也不应该产生任何编译错误因为方法是 static

请向我解释方法重写在 Java.

中的静态 classes 中是如何工作的
  1. 静态方法可以重写吗?如果是,那么注释 @Override 怎么会失败?
  2. 如果不能覆盖静态方法,那我的第三个代码块运行怎么没问题?
  3. 如果不能重写静态方法,那么 final 关键字有何不同?

你搞糊涂了overriding with hiding

首先,这里涉及不同的机制:Overriding and Shadowing (also called hiding)

1) 静态方法不能被覆盖,因为它们附加到它们在其中定义的 class。但是,您可以 shadow/hide 一个静态方法,就像您对 Parent/Childclass。这意味着,该方法在 Child class 中被替换,但在 Parent class.

中仍然可用

当您从那些 classes 的实例调用静态方法时(并且不使用 Class.staticMethod()调用)。

Parent parent = new Parent();
Child child1 = new Child();
Parent child2 = new Child();

parent.StaticMethod();
child1.StaticMethod();
child2.StaticMethod();

输出是

Static method from Parent
Static method from Child
Static method from Parent

答案是方法的调度。你可以抓住 source code here

2) 调度在 Parent class 上找到方法。没有动态调度,因为运行时类型用于查找方法句柄。它使用编译时类型。 提醒:从实例调用静态方法被认为是不好的做法,因为像上面这样的事情可能会发生并且很容易被忽视。

3) 使用 final 你声明该方法不能被覆盖 shadowed/hidden.

虽然不鼓励一口气问3个问题post,但我还是愿意回答的

  1. 不能覆盖静态方法,因为这样做没有意义。在你的情况下,如果你想覆盖静态方法,你可以调用该方法并在之后添加你自己的实现,或者你只创建另一个方法。

  2. 所以现在你知道静态方法不能被覆盖。但是你在问为什么第三个代码有效?第三个代码是带

    的代码

    public class 子级扩展父级 {}

对吧?虽然静态方法不能被覆盖,但是可以继承。你正在做的是继承 Parent 所以这完全没问题!

  1. 现在让我告诉您,在您的第一个代码示例中,您隐藏 Parent class 中的方法,而不是覆盖。这就是你得到输出的原因。 final 关键字意味着该方法可以 永远不会 被更改,甚至不能隐藏。这就是为什么。