java - 如果静态方法不能被覆盖,它如何在这里工作(对于 Java)?

标签 java overriding

我的理解是静态变量和静态方法属于一个类,而不是属于类对象。因此,静态方法的 Override 在 Java 中是行不通的,因为覆盖我们需要创建一个类的实例。但我今天尝试了一些与我对 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 类扩展了 Parent 类,但 doit 方法对于每个类都是独立的,因为它们是静态。所以不允许覆盖它们。

现在请按照下面的代码,其中 @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

为什么上面的代码可以编译运行?我期待 Child 类的方法 doit 出现编译错误,并且期待“找不到方法”。我不明白。

另外,请按照以下代码。在这里,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 方法都是静态的,所以即使是 final 关键字也不应该产生任何编译错误因为方法是static

请向我解释方法覆盖在 Java 中的静态类中是如何工作的。

  1. 可以覆盖静态方法吗?如果是,那么为什么注释 @Override 会失败?
  2. 如果静态方法不能被覆盖,那我的第三个代码块怎么运行得很好?
  3. 如果静态方法不能被覆盖,那么 final 关键字有何不同?

最佳答案

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

1) 静态方法不能被覆盖,因为它们附加到定义它们的类。但是,您可以像使用 Parent 一样隐藏/隐藏静态方法。/Child类(class)。这意味着,该方法在 Child 中被替换。类,但仍可从 Parent 获得类。

更明显的是,当您从这些类的实例调用静态方法(而不是使用 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

答案是方法的分派(dispatch)。你可以捕获source code here

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

3) 与 final您声明该方法不能被覆盖,也不能被隐藏/隐藏。

关于java - 如果静态方法不能被覆盖,它如何在这里工作(对于 Java)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32112692/

相关文章:

java - 具有自定义对象的二进制文件 I/O - Java

ios - Segue 没有被转入(swift 3)

c# - VB.Net 'Overridable' 对成员变量声明无效

c++ - 在 C++ 中重写继承

java - 创建类似 Facebook 的菜单

java - 如何将请求从同一个 JSP 文件发送到多个 Servlet?

java - 如何从自定义 ListView 中获取特定 View 并更改属性?

java - 仅在 Java SWT 中文本框的最后一行写入

java - 覆盖等于方法

php - 如何在 PasswordBroker Laravel 5 中覆盖 reset 和 validatePasswordWithDefaults