【问题标题】:How does the JLS specify the terms "abstract method", "concrete method" and "default method"?JLS 如何指定术语“抽象方法”、“具体方法”和“默认方法”?
【发布时间】:2020-05-14 00:09:57
【问题描述】:

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

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

【问题讨论】:

  • 注意:我不是要求对这些术语进行解释。这是一个“语言律师”问题。

标签: java default abstract jls


【解决方案1】:

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

根据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 定义。

【讨论】:

    【解决方案2】:

    抽象方法

    Java 语言规范 (JLS) Section 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();
    
        // ...
    
    }
    

    具体方法

    根据JLSSection 8.4.3.1,具体方法定义为:

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

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

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

    默认方法

    默认方法定义在 JLS Section 9.4:

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

    同样的部分还添加了:

    接口可以声明static 方法,这些方法无需引用特定对象即可调用。 static 接口方法不同于默认方法,默认方法是实例方法。

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

    这不应该用作抽象类的替代品。它是为特定目的而设计的,应该用于该目的。

    实际上,默认方法是使用default 关键字创建的:

    public interface Foo {
    
        public default void someMethod() {
            // ... some default implementation ...
        }
    }
    

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

    public class FooImpl implements Foo {
    
        @Override
        public void someMethod() {
            // ... some overriding implementation ...
        }
    }
    

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

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

    例如:

    public class FooImpl implements Foo {
    
        @Override
        public void someMethod() {
            Foo.super.someMethod();
        }
    }
    

    接口名称用作限定符是因为一个类可以实现多个接口(或者一个接口可以扩展多个接口)。如需更多信息,请参阅Explicitly calling a default method in Java

    【讨论】:

      猜你喜欢
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 2015-11-27
      • 2014-10-05
      • 1970-01-01
      • 2015-08-14
      • 2013-05-16
      • 1970-01-01
      相关资源
      最近更新 更多