得瑟一下jdk源代码解析,如何在运行时修改java final变量

先让各位看官看看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();
				}
			}
		}
	}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值