zoukankan      html  css  js  c++  java
  • Java接口的初始化

    背景

    接口与类真正有所区别的是前面讲述的四种“有且仅有”需要开始初始化场景中的第三种:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求其父接口全部都完成了初始化,只有在真正使用到父接口的时候(如引用接口中定义的常量)才会初始化。 ——《深入理解Java虚拟机:JVM高级特性与最佳实践》

    这里讲到引用接口中定义的常量会初始化接口,但是书中也写到引用类中的常量不会导致类被初始化,因为编译阶段已经将常量移动到常量池中了,两者的说法有一些矛盾让我很困惑。

    public class InterfaceInitTest {
    
        public static void main(String[] args) {
            System.out.println(Interface.CONSTANT_INT);
        }
    
    }
    
    interface Interface {
    
        int CONSTANT_INT = 1;
    
        Object CONSTANT_OBJECT = new Object();
    
        Object CONSTANT_OBJECT2 = new Object() {
            {
                System.out.println("interface init");
            }
        };
    
    }
    

    1

    Process finished with exit code 0

    可以看到没有接口并没有被初始化,这和我理解的是一样的,引用类中的常量不会导致类被初始化,引用接口中的常量也不会被初始化。

    但是稍微修改一下main函数的代码

    public class InterfaceInitTest {
    
        public static void main(String[] args) {
            System.out.println(Interface.CONSTANT_OBJECT);
        }
    
    }
    

    interface init
    java.lang.Object@14ae5a5

    Process finished with exit code 0

    可以看到同样是引用接口中的常量,有时候接口又会被初始化。

    通过在网上找到的一篇文章ConstantValue属性,里面提到常量池中只能引用到基本类型和String类型的字面量。这也就解答了我的困惑:类和接口在被引用常量的时候是否被初始化,取决于这个常量能够在编译时被放进常量池中(排除不支持的类型和运行时常量)。

    接口初始化的规则

    通过测试发现,以下几种情况接口会被初始化:

    1. 调用接口中不在常量池中的常量(对static字段的引用引发的初始化只会初始化实际定义的接口(尽管可以通过实现类,子接口的名称进行引用(而接口中的static方法不能被继承)))
    2. 调用接口中的静态方法
    3. 当初始化一个类时,将初始化这个类实现的所有的包含default方法的接口和超接口
    4. java.lang.reflect可能会导致接口初始化

    初始化接口本身不会导致任何超接口的初始化(注意和第3条的区别)

    对于这个问题我查阅了很多书籍和文章,都有讲得不太清楚的地方,所以不太确定结论是否正确,文章存在的疏漏读者也可以评论指正。

  • 相关阅读:
    ViewController生命周期
    Core Data 基本数据操作 增删改查 排序
    Core data 如何查看ObjectId
    NSArary自定义对象排序 NSComparator, compare
    tcp/ip协议学习笔记一
    常用mac/unix/linux命令
    IOS pin约束问题 存在间隙
    IOS 常用View属性设置
    ubuntu 16.04菜单栏不显示
    linux实用命令备忘
  • 原文地址:https://www.cnblogs.com/jrjrzivvv/p/13860182.html
Copyright © 2011-2022 走看看