文档

Java™教程
隐藏目录
获取和设置字段值
导航:反射API
教程:成员
部分:字段

获取和设置字段值

给定一个类的实例,可以使用反射来设置该类中字段的值。通常只在无法以常规方式设置值的特殊情况下才这样做。因为这种访问通常违反了类的设计意图,所以应该慎重使用。

Book类示例了如何设置长整型、数组和枚举字段的值。获取和设置其他基本类型的方法在Field中有描述。

import java.lang.reflect.Field;
import java.util.Arrays;
import static java.lang.System.out;

enum Tweedle { DEE, DUM }

public class Book {
    public long chapters = 0;
    public String[] characters = { "Alice", "White Rabbit" };
    public Tweedle twin = Tweedle.DEE;

    public static void main(String... args) {
	Book book = new Book();
	String fmt = "%6S:  %-12s = %s%n";

	try {
	    Class<?> c = book.getClass();

	    Field chap = c.getDeclaredField("chapters");
	    out.format(fmt, "before", "chapters", book.chapters);
  	    chap.setLong(book, 12);
	    out.format(fmt, "after", "chapters", chap.getLong(book));

	    Field chars = c.getDeclaredField("characters");
	    out.format(fmt, "before", "characters",
		       Arrays.asList(book.characters));
	    String[] newChars = { "Queen", "King" };
	    chars.set(book, newChars);
	    out.format(fmt, "after", "characters",
		       Arrays.asList(book.characters));

	    Field t = c.getDeclaredField("twin");
	    out.format(fmt, "before", "twin", book.twin);
	    t.set(book, Tweedle.DUM);
	    out.format(fmt, "after", "twin", t.get(book));

        // 生产代码应该更优雅地处理这些异常
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	}
    }
}

这是对应的输出:

$ java Book
BEFORE:  chapters     = 0
 AFTER:  chapters     = 12
BEFORE:  characters   = [Alice, White Rabbit]
 AFTER:  characters   = [Queen, King]
BEFORE:  twin         = DEE
 AFTER:  twin         = DUM

注意: 通过反射设置字段的值会带来一定的性能开销,因为必须进行各种操作,如验证访问权限。从运行时的角度来看,效果是相同的,操作就像在类代码中直接更改值一样具有原子性。

使用反射可能会导致一些运行时优化丢失。例如,以下代码高度可能会被Java虚拟机优化:
int x = 1;
x = 2;
x = 3;

使用Field.set*()的等效代码可能不会。



上一页:检索和解析字段修饰符
下一页:故障排除