先让各位看官看看sun的jdk Field类的代码,
/* * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang.reflect; import sun.reflect.FieldAccessor; import sun.reflect.Reflection; import sun.reflect.generics.repository.FieldRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; import sun.reflect.generics.scope.ClassScope; import java.lang.annotation.Annotation; import java.util.Map; import sun.reflect.annotation.AnnotationParser; /** * A {@code Field} provides information about, and dynamic access to, a * single field of a class or an interface. The reflected field may * be a class (static) field or an instance field. * * <p>A {@code Field} permits widening conversions to occur during a get or * set access operation, but throws an {@code IllegalArgumentException} if a * narrowing conversion would occur. * * @see Member * @see java.lang.Class * @see java.lang.Class#getFields() * @see java.lang.Class#getField(String) * @see java.lang.Class#getDeclaredFields() * @see java.lang.Class#getDeclaredField(String) * * @author Kenneth Russell * @author Nakul Saraiya */ public final class Field extends AccessibleObject implements Member { private Class<?> clazz; private int slot; // This is guaranteed to be interned by the VM in the 1.4 // reflection implementation private String name; private Class<?> type; private int modifiers; // Generics and annotations support private transient String signature; // generic info repository; lazily initialized private transient FieldRepository genericInfo; private byte[] annotations; // Cached field accessor created without override private FieldAccessor fieldAccessor; // Cached field accessor created with override private FieldAccessor overrideFieldAccessor; // For sharing of FieldAccessors. This branching structure is // currently only two levels deep (i.e., one root Field and // potentially many Field objects pointing to it.) private Field root; .....以下省略下面的这个函数可以从类的同名文件中载入一个Properties配置,将类的string类型变量赋予一个配置值,即使这个字段是final类型的也是可以的,看了上面代码的看官也许没反应过来,且听分说:
1.首先是Field类的modifiers字段设置为可访问(这个字段本来是private 是不可访问的),获得想要修改字段的Filed对象, 利用开放权限的Filed.modifiers的Filed利用反射修改字段的修饰符去掉final关键字,然后修改变量值,接着就是打扫战场,恢复原来的权限和final修饰
接着说下局限性,只在sun的jre 1.6 1.7 上测试过,其他的jre不敢保证,这个方法不推荐使用,但是你的代码担心被反编译,就把关键变量设置成final然后在需要的时候动态修改。记得把动态修改的代码用自定义classloader 加载进来,用asm动态生成代码也可以,这肯定让分析人看的直晕~~~
protected void load_conf() { // copy all right , barenx@163.com, 2011 String file = this.getClass().getName() + ".conf"; //file = this.getClass().getClassLoader().getResource(file).getFile(); final Properties conf = new Properties(); try { conf.load(new FileInputStream(file)); } catch (final Exception e) { e.printStackTrace(); return; } for (final Field field : this.getClass().getDeclaredFields()) { if ((field.getType() == String.class)) { final String fname = field.getName(); final String fvalue = conf.getProperty(fname); if ((null == fvalue) || (0 == fvalue.length())) { continue; } try { field.setAccessible(true); final Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); field.set(this, fvalue); modifiersField.setInt(field, field.getModifiers() | Modifier.FINAL); modifiersField.setAccessible(false); field.setAccessible(false); } catch (final Exception e) { e.printStackTrace(); } } } }