JLS 如何指定术语“抽象方法”、“具体方法”和“默认方法”?

Ste*_*n C 5 java default abstract jls

我在某些 StackOverflow 答案中看到了术语抽象方法具体方法默认方法的“不同”定义。

Java 语言规范给出的真正定义是什么?请在您的答案中包含相关的支持 JLS 参考。

Ste*_*n C 10

下面的链接/部分编号取自 Java 语言规范的 Java 11 版本。

根据JLS 8.4.3.1

abstract方法声明将方法作为成员引入,提供其签名(第 8.4.2 节)、结果(第 8.4.5 节)和 throws 子句(如果有)(第 8.4.6 节),但不提供实现(第 8.4 节) .7).没有的方法abstract 可以称为具体方法。

根据JLS 9.4

“默认方法是在带有default修饰符的接口中声明的实例方法。它的主体总是由一个块表示,它为实现该接口的任何类提供默认实现而不覆盖该方法。 默认方法与具体方法不同 ( §8.4.3.1),它们在类中声明,并且来自 私有接口方法,既不继承也不重写。”

所以根据这个分类法,实际上有 4 种方法:

  • 抽象方法,
  • 具体方法,
  • 默认方法和
  • 私有接口方法

请注意,JLS 8.4.3.1 没有提及finalstatic区分抽象方法和具体方法。

这些修饰符不能与abstract关键字一起使用。这意味着是staticfinal必须是具体方法的方法。这加强了 8.4.3.1 对具体方法的定义。


Jus*_*ano 5

抽象方法

Java 语言规范 (JLS)第 8.4.3.1 节中将抽象方法定义为:

抽象方法声明将方法作为成员引入,提供其签名(第 8.4.2 节)、结果(第 8.4.5 节)和 throws 子句(如果有)(第 8.4.6 节),但不提供实现(第 8.4 节) .7)。

实际上,抽象方法是定义了签名但未提供实现的任何方法。例如,接口中的方法和abstract抽象类中用关键字限定的方法都是抽象方法:

public interface Foo {
    void someAbstractMethod();
}

public abstract class Bar {

    public abstract someAbstractMethod();

    // ...

}
Run Code Online (Sandbox Code Playgroud)

具体方法

根据 JLS第 8.4.3.1 节,具体方法定义为:

不抽象的方法可以称为具体方法。

实际上,这意味着提供了实现的任何方法:

public FooImpl implements Foo {

    @Override
    public void someAbstractMethod() {
        // ... some implementation ...
    }

}
Run Code Online (Sandbox Code Playgroud)

默认方法

默认方法在 JLS第 9.4 节中定义:

默认方法是在具有默认修饰符的接口中声明的实例方法。它的主体总是由一个块表示,它为任何实现接口的类提供默认实现而不覆盖方法。默认方法不同于在类中声明的具体方法(第 8.4.3.1 节),也不同于既不继承也不重写的私有接口方法。

同一部分还增加了:

接口可以声明static方法,这些方法在不引用特定对象的情况下被调用。static接口方法不同于默认方法,默认方法是实例方法。

默认方法是为特定目的而创建的。在 JDK 8 中,函数式接口被添加到 Java 中。这需要更新接口以包含功能方法,但这样做将要求这些接口的所有现有实现(包括在第 3 方库和框架中)都需要提供实现。相反,Java 团队引入了默认方法,这些方法是提供默认实现的接口方法,当覆盖类没有提供实现时使用该实现。

这不应该用作抽象类的替代品。它旨在用于特定目的,并且应该用于该目的。

在实践中,默认方法是使用default关键字创建的:

public interface Foo {

    public default void someMethod() {
        // ... some default implementation ...
    }
}
Run Code Online (Sandbox Code Playgroud)

这个默认实现可以在具体的子类中被覆盖:

public class FooImpl implements Foo {

    @Override
    public void someMethod() {
        // ... some overriding implementation ...
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,根据 JLS第 9.4.1.1 节,可以使用super由接口名称限定的关键字在具体子类中访问方法的默认实现(默认方法的主体):

可以使用包含super由超级接口名称限定的关键字的方法调用表达式(第 15.12 节)访问覆盖的默认方法。

例如:

public class FooImpl implements Foo {

    @Override
    public void someMethod() {
        Foo.super.someMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

接口名称用作限定符,因为一个类可以实现多个接口(或者一个接口可以扩展多个接口)。有关更多信息,请参阅在 Java 中显式调用默认方法