groovy/java修改final变量的值

50 阅读1分钟

方案

  1. 通过反射找到对应的字段
  2. 修改modifiers为非final
  3. 设置值

代码(groovy4)

/**设置字段值,如果是final的会修改为非final再设值,会查找父类的私有字段进行设值
 * @objOrClz 对象(设置属性传对象)或类(设置静态变量传Class)
 * @fieldName 字段名
 * @newValue 新值
 * */
static void setObjFieldVal(Object objOrClz, String fieldName, Object newValue) throws Exception {
    Class clz
    if (objOrClz instanceof Class){
        clz=objOrClz
    }else{
        clz=objOrClz.getClass()
    }
    def tmp = clz
    boolean hasDone = false
    while (tmp!=Object.class&&clz!=GroovyObject.class&&tmp!=null){
        Field field
        try {
            field = tmp.getDeclaredField(fieldName)
        }catch (Exception ignored){
            tmp=tmp.superclass
            continue
        }
        field.accessible=true
        if (Modifier.isFinal(field.getModifiers())){
            def modifiersField=field.class.getDeclaredField('modifiers')
            modifiersField.accessible=true
            //修改为非final,这只对Field反射生效,不对直接访问生效
            modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL)
        }
        def isS = Modifier.isStatic(field.getModifiers())
        def t= field.type
        if (t.isPrimitive()){
            //基础数据类型需要转换
            switch (t){
                case boolean:
                    field.set(isS?null:objOrClz, newValue==null?false:(newValue as boolean))
                    break
                case char:
                    field.set(isS?null:objOrClz,newValue==null?(char)0:(newValue as char))
                    break
                case byte:
                    field.set(isS?null:objOrClz,newValue==null?(byte)0:(newValue as byte))
                    break
                case int:
                    field.set(isS?null:objOrClz,newValue==null?0:(newValue as int))
                    break
                case long:
                    field.set(isS?null:objOrClz,newValue==null?0L:(newValue as long))
                    break
                case float:
                    field.set(isS?null:objOrClz,newValue==null?0F:(newValue as float))
                    break
                case short:
                    field.set(isS?null:objOrClz,newValue==null?(short)0:(newValue as short))
                    break
                case double:
                    field.set(isS?null:objOrClz,newValue==null?0D:(newValue as double))
                    break
                default:
                    throw new RuntimeException(
                            "unsupported primitive type:${t.name} in class ${clz.name} var ${fieldName}")
            }
        }else{
            field.set(isS?null:objOrClz, newValue)
        }
        //如果有必要把set包起来在finally中设置回final:(modifiersField.setInt(field,field.getModifiers()&Modifier.FINAL))
        hasDone=true
        if (!Modifier.isPrivate(field.getModifiers())||isS){
            //静态变量及非私有属性不再向上查找父类
            break
        }else{
            tmp=tmp.superclass
        }
    }
    if (!hasDone){
        throw new NoSuchFieldException("class ${clz.name} does not have var ${fieldName}!")
    }
}