Groovy枚举类初始化异常分析

2021-01-06 09:25:34 浏览数 (1)

之前写过一些Groovy重载操作符(终极版)的文章,中间用了内部的枚举类,然后通过一个static HPS getInstance(char c)方法获取不同的枚举对象,今天想着把中间的字符去掉,放在枚举类属性中。却发现了一个错误,又是一顿操作猛如虎,重启缓存二百五。

经过多方求证失败后,我开始还原代码,一点点点排查,终于找到了问题的症结所在。下面分享一下这个坑。

错误的代码

代码语言:javascript复制
package com.fun.ztest.groovy


import com.fun.moco.MocoServer

class MocoDemo extends MocoServer {


    public static void main(String[] args) {
       println FunTester.FUN

    }


    static enum FunTester {

        FUN('3'),TESTER('2')

        char name

        FunTester(char name) {
            this.name = name
        }
    }
}

然后运行,控制台输出:

代码语言:javascript复制
INFO-> 当前用户:fv,IP:10.60.131.54,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
Exception in thread "main" java.lang.ExceptionInInitializerError
 at sun.misc.Unsafe.ensureClassInitialized(Native Method)
 at sun.reflect.UnsafeFieldAccessorFactory.newFieldAccessor(UnsafeFieldAccessorFactory.java:43)
 at sun.reflect.ReflectionFactory.newFieldAccessor(ReflectionFactory.java:142)
 at java.lang.reflect.Field.acquireFieldAccessor(Field.java:1088)
 at java.lang.reflect.Field.getFieldAccessor(Field.java:1069)
 at java.lang.reflect.Field.get(Field.java:393)
 at org.codehaus.groovy.reflection.CachedField.getProperty(CachedField.java:55)
 at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:1804)
 at groovy.lang.MetaClassImpl.getProperty(MetaClassImpl.java:3797)
 at org.codehaus.groovy.runtime.callsite.ClassMetaClassGetPropertySite.getProperty(ClassMetaClassGetPropertySite.java:50)
 at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:298)
 at com.fun.ztest.groovy.MocoDemo.main(MocoDemo.groovy:10)
Caused by: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: com.fun.ztest.groovy.MocoDemo$FunTester(String, Integer, String)
 at groovy.lang.MetaClassImpl.createCachedConstructor(MetaClassImpl.java:1613)
 at groovy.lang.MetaClassImpl.selectConstructorAndTransformArguments1(MetaClassImpl.java:1639)
 at groovy.lang.MetaClassImpl.selectConstructorAndTransformArguments(MetaClassImpl.java:1561)
 at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.selectConstructorAndTransformArguments(ScriptBytecodeAdapter.java:250)
 at com.fun.ztest.groovy.MocoDemo$FunTester.$INIT(MocoDemo.groovy)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:497)
 at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:101)
 at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:323)
 at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.invoke(StaticMetaMethodSite.java:44)
 at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:100)
 at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:55)
 at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:196)
 at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:224)
 at com.fun.ztest.groovy.MocoDemo$FunTester.<clinit>(MocoDemo.groovy)
 ... 12 more

Process finished with exit code 1

乍一看,都是什么神仙错误,居然是初始化异常,而且重点是异常信息Could not find matching constructor for: com.fun.ztest.groovy.MocoDemo$FunTester(String, Integer, String),我始终无法想清楚我在哪里用了这个构造方法。

原因剖析

经过一点点点还原代码,终于发现是添加枚举对象的时候报错的,再一想,Groovy里面对于双引号""和单引号‘’是不区分charString的,应该是这个原因导致枚举类初始化不成功。

使用双引号""和单引号‘’的字符或者字符串对于Groovy都是String类型的对象。

代码语言:javascript复制
    public static void main(String[] args) {
        println "3".class.getName()
        println '3'.class.getName()
    }

控制台输出:

代码语言:javascript复制
INFO-> 当前用户:fv,IP:10.60.131.54,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
java.lang.String
java.lang.String

Process finished with exit code 0

改正

所以在写枚举类对象的时候,需要特殊处理一下字符或者字符串,正确的使用方法如下:

代码语言:javascript复制
class MocoDemo extends MocoServer {


    public static void main(String[] args) {
       println FunTester.FUN

    }


    static enum FunTester {

        FUN((char)'3'),TESTER((char)'2')

        char name

        FunTester(char name) {
            this.name = name
        }
    }
}

控制台输出

代码语言:javascript复制
INFO-> 当前用户:fv,IP:10.60.131.54,工作目录:/Users/fv/Documents/workspace/fun/,系统编码格式:UTF-8,系统Mac OS X版本:10.16
FUN

Process finished with exit code 0

0 人点赞