为什么类静态方法被继承,而不是接口静态方法?

我理解在Java中,静态方法就像实例方法一样被继承,不同之处在于当它们被重新声明时,父实现是隐藏的而不是被覆盖的。好吧,这是有道理的。但是,Java教程指出:

接口中的静态方法永远不会被继承。

为什么?常规方法和接口静态方法有什么区别?

让我澄清一下我说静态方法可以继承的意思:

class Animal {
    public static void identify() {
        System.out.println("This is an animal");
    }
}
class Cat extends Animal {}

public static void main(String[] args) {
    Animal.identify();
    Cat.identify(); // This compiles, even though it is not redefined in Cat.
}

然而

interface Animal {
    public static void identify() {
        System.out.println("This is an animal");
    }
}
class Cat implements Animal {}

public static void main(String[] args) {
    Animal.identify();
    Cat.identify(); // This does not compile, because interface static methods do not inherit. (Why?)
}

答案 1

这是我的猜测。

因为如果扩展则只能扩展一个类那么它只有一个含义。 可以实现多个接口,每个接口都可以有一个静态实现。因此,编译器不会知道选择哪一个?CatCatAnimalCat.identifyCat

然而,正如提交人所指出的,

Java已经有了这个问题,使用默认方法。如果两个接口声明默认 void 标识(),则使用哪一个?这是一个编译错误,你必须实现一个重写方法(可能只是Animal.super.identify())。所以Java已经解决了默认方法的这个问题 - 为什么不为静态方法呢?

如果我再猜一次,我会说实现是 vtable 的一部分。与它不可能。main 函数必须绑定到某些内容。在编译时,编译器可以替换,但如果重新编译,代码将与现实不符,但与包含main的类不匹配。defaultCatstaticCat.identifyAnimal.identifyCat


答案 2

Java 8 之前,您无法在 .这个问题对此进行了大量讨论。我将参考这个答案(由用户@JamesA.Rosen)来解释为什么Java设计人员最初可能不希望使用方法:staticinterfacestaticinterface

这里有几个问题在起作用。第一个问题是声明静态方法而不定义它的问题。这是区别

public interface Foo {
  public static int bar();
}

public interface Foo {
  public static int bar() {
    ...
  }
}

Java也不允许,但它可以允许第二种。第一个是不可能的,因为Espo提到的原因:你不知道哪个实现类是正确的定义。

Java可以允许后者,只要它将接口视为一等对象。Ruby的模块,大约相当于Java的接口,完全允许:

module Foo
  def self.bar
    ...
  end
end

但是,自 Java 8 发布以来,您实际上可以在 .defaultstaticinterface

我将在这里引用这个来源很多。这是最初的问题:

Java 的接口语言功能允许您使用抽象方法声明接口,并在实现接口的类中提供这些方法的实现。您需要实现每个方法,当有许多方法要实现时,这是很麻烦的。此外,发布接口后,您无法在不破坏源代码和二进制兼容性的情况下向其添加新的抽象方法。

这是Java 8提供的解决方案:default

Java 8 通过改进接口来支持缺省方法和静态方法来解决这些问题。默认方法是在接口中定义的实例方法,其方法标头以默认关键字开头;它还提供了一个代码体。实现接口的每个类都继承接口的默认方法,并且可以重写它们

对于 :static

静态方法是与定义它的类相关联的方法,而不是与从该类创建的任何对象相关联的方法。类的每个实例共享该类的静态方法。Java 8 还允许在接口中定义静态方法,以便它们能够帮助缺省方法。

实现包含静态方法的接口时,静态方法仍然是接口的一部分,而不是实现类的一部分。因此,不能在方法前面加上类名的前缀。相反,您必须在方法前面加上接口名称

例:

interface X
{
   static void foo()
   {
      System.out.println("foo");
   }
}

class Y implements X
{
}

public class Z 
{
   public static void main(String[] args)
   {
      X.foo();
      // Y.foo(); // won't compile
   }
}

表达式不会编译,因为它是接口的静态成员,而不是类 的静态成员。Y.foo()foo()XY


推荐