Java 是否可以重写派生类中的静态方法?

Java 是否可以重写派生类中的静态方法?,java,static,Java,Static,我在基类中定义了一个静态方法,我想在它的子类中重写这个方法,有可能吗 我试过了,但没有达到预期效果。当我创建类B的实例并调用其callMe()方法时,调用了类A中的静态foo()方法 public abstract class A { public static void foo() { System.out.println("I am base class"); } public void callMe() { foo(); } } Public class

我在基类中定义了一个静态方法,我想在它的子类中重写这个方法,有可能吗

我试过了,但没有达到预期效果。当我创建类B的实例并调用其callMe()方法时,调用了类A中的静态foo()方法

public abstract class A {
  public static void foo() {
    System.out.println("I am base class");
  }

  public void callMe() {
    foo();
  }
}

Public class B {
  public static void foo() {
      System.out.println("I am child class");
  }
}
不可能


一些类似的(不同的)问题和。

静态方法调用在编译时得到解决(无动态调度)

给予


在Java中,静态方法查找是在编译时确定的,不能适应编译后加载的子类。

只需添加一个原因即可。通常,当您调用一个方法时,该方法所属的对象用于查找适当的实现。通过让对象提供自己的方法而不是使用父对象提供的方法,可以重写方法


在静态方法的情况下,没有对象来告诉您要使用哪个实现。这意味着编译器只能使用声明的类型来选择要调用的方法的实现。

静态方法是在编译时解析的。因此,如果要调用父类方法,则应使用以下类名或实例显式调用

A.foo();


我可以重写静态方法吗?

很多人都听说不能重写静态方法。这是真的,你不能。但是,可以编写如下代码:

class Foo {
    public static void method() {
        System.out.println("in Foo");
    }
}

class Bar extends Foo {
    public static void method() {
        System.out.println("in Bar");
    }
}
这可以编译并运行得很好。这不是一个静态方法重写另一个静态方法的例子吗?答案是否定的——这是一个静态方法隐藏另一个静态方法的例子。如果您试图重写一个静态方法,编译器实际上并不会阻止您——它只是不会做您认为它会做的事情

那有什么区别呢?

简单地说,当您重写一个方法时,您仍然可以获得运行时多态性的好处,而当您隐藏时,则不会。那是什么意思?请看下面的代码:

class Foo {
    public static void classMethod() {
        System.out.println("classMethod() in Foo");
    }

    public void instanceMethod() {
        System.out.println("instanceMethod() in Foo");
    }
}

class Bar extends Foo {
    public static void classMethod() {
        System.out.println("classMethod() in Bar");
    }

    public void instanceMethod() {
        System.out.println("instanceMethod() in Bar");
    }
}

class Test {
    public static void main(String[] args) {
        Foo f = new Bar();
        f.instanceMethod();
        f.classMethod();
    }
}
如果运行此命令,则输出为

条形图中的instanceMethod()
Foo中的classMethod()

为什么我们从Bar获得instanceMethod,而从Foo获得classMethod()?我们不是使用同一个实例f来访问这两个吗?是的,我们是——但由于一个是覆盖的,另一个是隐藏的,我们看到了不同的行为

由于instanceMethod()是(drum roll please…)一个实例方法,其中Bar覆盖来自Foo的方法,因此JVM在运行时使用实例f的实际类来确定要运行的方法。虽然f被声明为Foo,但我们创建的实际实例是一个新的Bar()。因此在运行时,JVM发现f是一个Bar实例,因此它在Bar中调用instanceMethod(),而不是在Foo中调用instanceMethod()。对于实例方法,Java通常就是这样工作的

但使用classMethod()时。因为它是一个类方法,编译器和JVM不需要实际的实例来调用该方法。即使您提供了一个(我们已经提供了:f引用的实例),JVM也不会查看它。编译器将只查看引用的声明类型,并使用该声明类型在编译时确定调用哪个方法。由于f被声明为Foo类型,编译器查看f.classMethod()并确定它的意思是Foo.classMethod。f引用的实例实际上是一个Bar并不重要,对于静态方法,编译器只使用声明的引用类型。这就是我们所说的静态方法没有运行时多态性的意思


因为实例方法和类方法在行为上有这种重要的区别,所以我们使用不同的术语——“覆盖”实例方法和“隐藏”类方法来区分这两种情况。当我们说你不能重写一个静态方法时,这意味着即使你写的代码看起来像是重写了一个静态方法(就像这个页面顶部的第一个Foo和Bar),它也不会表现得像一个被重写的方法。要了解更多信息,请参见简而言之,静态方法重写不是多态性,而是“方法隐藏”。 重写静态方法时,将无法访问基类方法,因为它将被派生类隐藏。。
使用super()会引发编译时错误。

首先,你不应该从对象调用静态方法,你应该从类中调用它。我改变了主意,写了“无动态调度”,因为这是涉及的一般概念。正确的术语是“超类”和“子类”,而不是“基类”和“子类”.我只是抄了粘贴好的MartinDenny2069的问题。我改变了帖子以反映你的建议。
 A a = new A();
 a.foo();
class Foo {
    public static void method() {
        System.out.println("in Foo");
    }
}

class Bar extends Foo {
    public static void method() {
        System.out.println("in Bar");
    }
}
class Foo {
    public static void classMethod() {
        System.out.println("classMethod() in Foo");
    }

    public void instanceMethod() {
        System.out.println("instanceMethod() in Foo");
    }
}

class Bar extends Foo {
    public static void classMethod() {
        System.out.println("classMethod() in Bar");
    }

    public void instanceMethod() {
        System.out.println("instanceMethod() in Bar");
    }
}

class Test {
    public static void main(String[] args) {
        Foo f = new Bar();
        f.instanceMethod();
        f.classMethod();
    }
}