具有默认方法的接口何时初始化?

2024-03-30

在搜索 Java 语言规范来寻找答案时这个问题 https://stackoverflow.com/questions/23093470/java-order-of-initialization-and-instantiation#23093470, 我学会了that http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4

在初始化一个类之前,它的直接超类必须是 初始化,但类实现的接口不是 已初始化。同样,接口的超级接口也不是 在接口初始化之前进行初始化。

出于自己的好奇心,我尝试了一下,不出所料,界面InterfaceType没有初始化。

public class Example {
    public static void main(String[] args) throws Exception {
        InterfaceType foo = new InterfaceTypeImpl();
        foo.method();
    }
}

class InterfaceTypeImpl implements InterfaceType {
    @Override
    public void method() {
        System.out.println("implemented method");
    }
}

class ClassInitializer {
    static {
        System.out.println("static initializer");
    }
}

interface InterfaceType {
    public static final ClassInitializer init = new ClassInitializer();

    public void method();
}

该程序打印

implemented method

但是,如果接口声明了default方法,然后初始化就会发生。考虑InterfaceType接口给出为

interface InterfaceType {
    public static final ClassInitializer init = new ClassInitializer();

    public default void method() {
        System.out.println("default method");
    }
}

那么上面的相同程序将打印

static initializer  
implemented method

换句话说,static接口的字段已初始化(详细初始化过程中的步骤 9 http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4)和static执行正在初始化的类型的初始值设定项。这意味着接口已初始化。

我在 JLS 中找不到任何表明这种情况应该发生的内容。不要误会我的意思,我知道如果实现类没有提供该方法的实现,则应该发生这种情况,但如果提供了怎么办? Java 语言规范中是否缺少此条件,我是否遗漏了某些内容,或者我是否错误地解释了它?


这是一个非常有趣的问题!

这好像是JLS 第 12.4.1 节 http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.1应该明确地涵盖这一点。但是,Oracle JDK 和 OpenJDK(javac 和 HotSpot)的行为与此处指定的不同。特别是,本节中的示例 12.4.1-3 涵盖了接口初始化。示例如下:

interface I {
    int i = 1, ii = Test.out("ii", 2);
}
interface J extends I {
    int j = Test.out("j", 3), jj = Test.out("jj", 4);
}
interface K extends J {
    int k = Test.out("k", 5);
}
class Test {
    public static void main(String[] args) {
        System.out.println(J.i);
        System.out.println(K.j);
    }
    static int out(String s, int i) {
        System.out.println(s + "=" + i);
        return i;
    }
}

其预期输出为:

1
j=3
jj=4
3

事实上我得到了预期的输出。但是,如果在接口中添加默认方法I,

interface I {
    int i = 1, ii = Test.out("ii", 2);
    default void method() { } // causes initialization!
}

输出更改为:

1
ii=2
j=3
jj=4
3

这清楚地表明了该接口I正在初始化,之前没有初始化!仅存在默认方法就足以触发初始化。不必调用或重写甚至提及默认方法,抽象方法的存在也不会触发初始化。

我的猜测是 HotSpot 实现希望避免将类/接口初始化检查添加到关键路径中invokevirtual称呼。在 Java 8 和默认方法之前,invokevirtual永远不可能最终在接口中执行代码,所以这不会出现。人们可能会认为这是类/接口准备阶段的一部分(JLS 12.3.2 http://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.3.2)它初始化方法表之类的东西。但也许这太过分了,意外地进行了完全初始化。

I've 提出这个问题 http://mail.openjdk.java.net/pipermail/compiler-dev/2014-April/008733.html在 OpenJDK 编译器开发邮件列表上。曾经有一个亚历克斯·巴克利的回复 http://mail.openjdk.java.net/pipermail/compiler-dev/2014-April/008734.html(JLS 的编辑),他在其中针对 JVM 和 lambda 实现团队提出了更多问题。他还指出,这里的规范中有一个错误,其中说“T 是一个类,并且调用 T 声明的静态方法”,如果 T 是一个接口,也应该适用。因此,这里可能同时存在规范和 HotSpot 错误。

披露:我在 Oracle 工作,使用 OpenJDK。如果人们认为这给了我在获得这个问题的奖金方面不公平的优势,我愿意对此保持灵活性。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有默认方法的接口何时初始化? 的相关文章

  • 将嵌套的 ArrayList 转换为 Java List

    我有这个方法 public List
  • 如何正确地将MapStruct与Eclipse集成? (包括Lombok java代理)

    我愿意在一些官方项目中使用MapStruct 所以我决定先对其进行一些测试 我需要让它与 eclipse 集成工作 并遵循 MapStruct 网站上提供的所有说明 但是 到目前为止还没有运气 有人成功实现了这种整合吗 如果是的话我可以缺少
  • 如何实现 Eclipse 清理和构建(又名重建)?

    我删除了我的 binEclipse Indigo 中的文件夹 与 Helios 非常相似 现在我想知道如何重建我的 Java 项目 我只是找不到像 Netbeans 中那样的按钮 对于 Eclipse 您可以在下面找到重建选项项目 gt 清
  • 从插件设置 Maven 属性

    我在这里阅读了一些关于如何从 Maven 插件设置属性的问题 其中大多数讨论了应用程序的版本号 似乎没有简单的方法可以做到这一点 我发现的最佳解决方案是拥有一个从插件更新的 filter properties 文件 并由主 pom 文件使用
  • Jackson反序列化SNS消息错误MismatchedInputException

    我正在编写一个通过 SNS HTTP 请求处理来自 Amazon Simple Email Service 的回调的功能 我想将亚马逊提供的消息解析为本地对象结构 问题是 SNS 将 JSON 消息包装成字符串 并且 Jackson 无法解
  • 如何为Spring Boot中的所有控制器指定前缀?

    我有控制器映射到 user and order RestController RequestMapping users public class UserController RestController RequestMapping or
  • 确定列表编号是否连续

    我在 Java 工作 我有一个无序列表 包含 5 个数字 范围从 0 100 没有重复 我想检测其中 3 个数字是否连续且没有间隙 例子 9 12 13 11 10 true 17 1 2 3 5 true 19 22 23 27 55 f
  • Java 增强型 For-Loop 比传统的更快?

    所以我的理解是 增强的 for 循环应该更慢 因为它们必须使用迭代器 但是我的代码提供了混合结果 是的 我知道循环逻辑占用了循环中花费的大部分时间 对于少量迭代 100 1000 增强的 for 循环在使用和不使用 JIT 的情况下似乎都要
  • 使用 Bouncy Castle 重建 ED25519 按键 (Java)

    Bouncy Castle 的最新 测试版 版本 bcprov jdk15on 161b20 jar 支持 ED25519 和 ED448 EC 加密以进行签名 我设置了这个完整的工作示例 它按预期工作 我的问题 我是否正确重建了私钥和公钥
  • Junit测试中LocalDateTime反序列化的问题

    我有问题LocalDateTime反序列化Junit测试 我有简单的REST API返回一些DTO目的 当我呼叫端点时 响应没有问题 它是正确的 然后我尝试编写单元测试 得到MvcResult并使用ObjectMapper将其转换为我的DT
  • Java OR 运算符优先级

    如何在 Java 中以 if 的方式链接条件语句b是假的 不如不检查c If a and c是假的 并且b是真的 确实c会被检查吗 if a b c 我正在寻找 PHP 所拥有的类似功能 但两者之间存在差异OR and 爪哇 如果左操作数是
  • 写入作为 Jar 文件中的资源包含的 Java 属性文件

    有没有办法修改作为资源存储在 Jar 文件中的属性文件中的属性值 这就是我正在尝试处理的场景 我有一个属性文件作为资源存储在我的 Jar 文件中 有一些系统特定的属性 例如路径 我希望能够为我想要运行 Jar 文件的系统更改此设置 最好的解
  • 在类路径中使用通配符调用 java 失败

    我当前目录中有一些 jar 它们都需要位于类路径中 因此我想对类路径使用通配符约定 命令行是 java exe classpath org python util jython args 但是我收到这个错误 Exception in thr
  • Jackson 中没有注释的多态反序列化

    我有一个CloudEvent
  • 使用 JPA 存储库保留 Spring Batch ItemWriter 的问题

    我对春季批次有疑问ItemWriter它依赖于 JPA 存储库来更新数据 这里是 Component public class MessagesDigestMailerItemWriter implements ItemWriter
  • Java 8 Nashorn:控制台几乎无法使用

    我在 OSX 10 9 2 上使用 Java 8 build 1 8 0 b132 我正在使用 Java 8 中的新 JavaScript 运行时 Nashorn 我在用Library Java JavaVirtualMachines jd
  • 启动 Firefox 并等待其关闭

    Question 我想启动 Firefox 网络浏览器作为访问特定网站的过程 然后等到它关闭 一种特殊情况是浏览器可能已经打开并正在运行 因为用户可能已经访问过某个网站 在这种情况下 浏览器可能会在现有窗口中打开一个新选项卡 并且新启动的进
  • 自动将通配符导入重构为 IntelliJ 中的显式导入(适用于 Scala/Java)

    考虑下面的代码 是否可以让 IntelliJ 自动将每个通配符导入重构为显式导入 无论范围内使用什么 例如import scalatags JsDom all into import scalatags JsDom all ol li di
  • JAVAFX 缩放、ScrollPane 滚动

    I have JAVAFX application with zoom and scale as described here Scale at pivot point in an already scaled node https sta
  • 只有创建视图层次结构的原始线程才能触摸其视图。在安卓上[重复]

    这个问题在这里已经有答案了 我只是一个初学者 所以请原谅我问一个可能愚蠢的问题 我不明白只有创建视图层次结构的原始线程才能触摸其视图的含义 请有人告诉我为什么会发生此错误以及如何解决此问题 ThankYou 这是我的班级 public cl

随机推荐