Kotlin enum类与companion设计的不协调--NPE导致ClassNotFoundException, Could not initialize class.

在Kotlin 1.1.0环境中,将原本的Java enum类转换为Kotlin时,由于Kotlin使用companion object代替静态成员,可能导致运行时错误。当enum实例尝试访问companion object的字段时,由于companion对象尚未初始化,产生NPE,进而引发ClassNotFoundException。解决方案包括将companion object移到单独的类或回归Java实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境: JDK8+kotlin 1.1.0
构建工具:Maven 3

项目中有一个定义报警类型的enum类最开始使用java编写, 后来改成了kotlin. IDE和编译都没有提示错误, 运行时却发现错误.ClassNotFoundException, Could not initialize class.

原来是kotlin使用companion代替static, 而enum类是在类初始化时就初始化实例, 如果在enum实例中引入到了companion object中的字段, ide和编译器都不会提示错误, 但是运行那么就会导致enum类初始化失败. 因为初始化实例时, companion object还没有初始化. 引用其字段, 导致NPE, 类初始化失败, 导致ClassNotFoundException, Could not initialize class.

Java代码

public enum AlarmType {
    MEMORY("memory", AlarmType.CONTAINER_TYPE, true),
    CPU("cpu", AlarmType.CONTAINER_TYPE, true);

    public static final int DEFAULT_TYPE = 0;
    public static final int CONTAINER_TYPE = 1;
    public static final int DOCKER_DAEMON_TYPE = 2;
    public static final int AGENT_TYPE = 3;

    private String type;
    private int generalType;

    AlarmType(String type, int generalType) {
        this.type = type;
        this.generalType = generalType;
    }
}

kotlin代码

kotlin中没有static的概念, 由companion object来代替. 我将以上的代码修改为kotlin时为以下的代码.

enum class AlarmType(val type: String, val generalType: Int) {
    MEMORY("memory", AlarmType.CONTAINER_TYPE),
    CPU("cpu", AlarmType.CONTAINER_TYPE);

    companion object {
        public val DEFAULT_TYPE = 0
        public val CONTAINER_TYPE = 1
        public val DOCKER_DAEMON_TYPE = 2
        public val AGENT_TYPE = 3
    }
}

kotlin字节码反编译

IDE没有报错, 编译也没有报错. 运行时却发现不能运行. 报ClassNotFoundException异常, Could not initialize class. 我将kotlin生成的class字节码用jd-gui反编译看到以下代码.(适度精简)
由1和2处的代码, 可知, 在enum类中, 实例的初始化是在类加载完后, static代码块中运行, 因为在kotlin中使用companion object代替static, 代码从Companion中取值来实例化enum的实例时, 却发现Companion对象为空, 空指针错误, 进而导致无法初始化类, 导致ClassNotFoundException.

public enum AlarmType {

    private final String type;
    public  static final Companion Companion;
    private static final int DEFAULT_TYPE = 0;
    private static final int CONTAINER_TYPE = 1;
    private static final int DOCKER_DAEMON_TYPE = 2;
    private static final int AGENT_TYPE = 3;

    static {
        //enum类是在静态代码块中就初始化实例. 因为kotlin中, 使用companion替代static, 所以, 下面用了Companion对象. 在类初始化时, 导致NPE, 导致类不能初始化
        AlarmType[] tmp6_2 = new AlarmType[2];     //1
        tmp6_2[0] =
                (MEMORY = new AlarmType("MEMORY", 0, "memory", Companion.getCONTAINER_TYPE()));
        AlarmType[] tmp32_6 = tmp6_2;
        tmp32_6[1] =
                (CPU = new AlarmType("CPU", 1, "cpu", Companion.getCONTAINER_TYPE()));
        $VALUES = tmp32_6;
        //在初始化实例之后, 才初始化Companion对象. 导致出问题
        Companion = new Companion(null); //2
    }

    private final int generalType;

    protected AlarmType(String type, int generalType) {
        this.type = type;
        this.generalType = generalType;
    }

    public static final class Companion {
        public final int getDEFAULT_TYPE() {
            return AlarmType.access$getDEFAULT_TYPE$cp();
        }

        public final int getCONTAINER_TYPE() {
            return AlarmType.access$getCONTAINER_TYPE$cp();
        }

        public final int getDOCKER_DAEMON_TYPE() {
            return AlarmType.access$getDOCKER_DAEMON_TYPE$cp();
        }

        public final int getAGENT_TYPE() {
            return AlarmType.access$getAGENT_TYPE$cp();
        }
    }
  }

解决方案

改回java, 或者将companion object移动到另外一个类中. 这样enum初始化类执行static代码时就不会引用未初始化的Companion了.

总结

新语言还是有坑, 谷歌上都没有搜到这个错误. 如果是不应该这样用, 那么IDE和编译器就应该提示错误, 而不是等到运行时才报错.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值