Stay Hungry Stay Foolish

Java反射API简介

Posted on By Jun Xi Gu

本文是对Java管网上反射API教程的个人总结,代码和测试用例均来自管网


Java反射 是一种强大的工具,能让开发人员在运行时获取和操作类,接口,域,方法的信息,其应用范围不广,但能跨过静态类型的约束。

应用范围:

  • 动态的扩展类的功能:如动态代理
  • 类信息浏览器、可视化开发工具
  • 调试器、测试工具

虽然反射很强大,但适用场景不多,而且使用是有代价的,所以能不用就不用

代价

  • 性能不足:因缺少编译器的代码优化
  • 安全约束情况复杂:动态的代码可能运行在不同的安全管理器中,受到不同的安全约束
  • 破坏封装:通过反射能无视修饰符的限制来访问类的成员

Java反射常用的API主要包括访问和操作类,方法,域,构造器,数组和枚举的API

类(Class)反射API

常用的类反射API主要包括:获取Class对象,获取类的访问修饰符和各种类型信息,获取类成员的信息

获取Class对象的API

Object.getClass() 通过一个对象来获取它的class的对象,例如

Class<String> c = "foo".getClass();

Set<String> s = new HashSet<String>();
Class<Set<String>>> c = s.getClass();

boolean b;
Class c = b.getClass(); // compile-time error

注意,基本类型的变量不能通过getClass获取Class对象

.class语法 通过“.class”语法来获取Class对象

Class<Boolean> c = boolean.class; // boxing type

Class<PrintStream> c = java.io.PrintStream.class;

Class<int[][][]> c = int[][][].class;

Class.forName() 通过Class的静态方法和class的全限定名来获取Class对象

Class c = Class.forName("com.duke.MyLocaleServiceProvider");

Class cStringArray = Class.forName("[[Ljava.lang.String;");

.type语法 可以通过.TYPE语法来获取基本类型包装类的Class对象,但其实可以用.class语法代替

Class的一些其他API

Class.getSuperclass() 获取父类

Class c = javax.swing.JButton.class.getSuperclass();

Class.getClasses() 获取所有在Class对象中声明的或继承而来的嵌套类,接口,枚举

Class<?>[] c = Character.class.getClasses();

Class.getDeclaredClasses() 获取所有在Class对象中声明的嵌套类,接口,枚举

Class<?>[] c = Character.class.getDeclaredClasses();

Class.getDeclaringClass()
java.lang.reflect.Field.getDeclaringClass()
java.lang.reflect.Method.getDeclaringClass()
java.lang.reflect.Constructor.getDeclaringClass()

嵌套类和成员通过以上API来获取外层的类,但匿名类需要不行,需要使用Class.getEnclosingClass

import java.lang.reflect.Field;

Field f = System.class.getField("out");
Class c = f.getDeclaringClass();
The field out is declared in System.
public class MyClass {
	static Object o = new Object() {
		public void m() {} 
	};
	static Class<c> = o.getClass().getEnclosingClass();
}

Class c = Thread.State.class().getEnclosingClass();
The enclosing class of the enum Thread.State is Thread.
public class MyClass {
	static Object o = new Object() { 
		public void m() {} 
	};
	static Class<c> = o.getClass().getEnclosingClass(); //MyClass
}

获取类的修饰符和类型信息

Class.getModifiers() 通过Class.getModifiers()来获取类的修饰符,另外java.lang.reflect.Modifier 有很多API来查看修饰符信息

c.getTypeParameters 通过c.getTypeParameters来获取class声明中的泛型变量

c.getGenericInterfaces() 通过c.getGenericInterfaces()获取class所实现的接口

c.getSuperclass() 通过c.getSuperclass()获取class的父类

c.getAnnotations() 通过c.getAnnotations()获取class声明中的注解

示例代码来源

import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;

public class ClassDeclarationSpy {
	public static void main(String... args) {
	try {
		Class<?> c = Class.forName(args[0]);
		out.format("Class:%n  %s%n%n", c.getCanonicalName());
		out.format("Modifiers:%n  %s%n%n",
			   Modifier.toString(c.getModifiers()));

		out.format("Type Parameters:%n");
		TypeVariable[] tv = c.getTypeParameters();
		if (tv.length != 0) {
		out.format("  ");
		for (TypeVariable t : tv)
			out.format("%s ", t.getName());
		out.format("%n%n");
		} else {
		out.format("  -- No Type Parameters --%n%n");
		}

		out.format("Implemented Interfaces:%n");
		Type[] intfs = c.getGenericInterfaces();
		if (intfs.length != 0) {
		for (Type intf : intfs)
			out.format("  %s%n", intf.toString());
		out.format("%n");
		} else {
		out.format("  -- No Implemented Interfaces --%n%n");
		}

		out.format("Inheritance Path:%n");
		List<Class> l = new ArrayList<Class>();
		printAncestor(c, l);
		if (l.size() != 0) {
		for (Class<?> cl : l)
			out.format("  %s%n", cl.getCanonicalName());
		out.format("%n");
		} else {
		out.format("  -- No Super Classes --%n%n");
		}

		out.format("Annotations:%n");
		Annotation[] ann = c.getAnnotations();
		if (ann.length != 0) {
		for (Annotation a : ann)
			out.format("  %s%n", a.toString());
		out.format("%n");
		} else {
		out.format("  -- No Annotations --%n%n");
		}

		// production code should handle this exception more gracefully
	} catch (ClassNotFoundException x) {
		x.printStackTrace();
	}
	}

	private static void printAncestor(Class<?> c, List<Class> l) {
	Class<?> ancestor = c.getSuperclass();
 	if (ancestor != null) {
		l.add(ancestor);
		printAncestor(ancestor, l);
 	}
	}
}

一些测试示例

$ java ClassDeclarationSpy java.util.concurrent.ConcurrentNavigableMap
Class:
  java.util.concurrent.ConcurrentNavigableMap

Modifiers:
  public abstract interface

Type Parameters:
  K V

Implemented Interfaces:
  java.util.concurrent.ConcurrentMap<K, V>
  java.util.NavigableMap<K, V>

Inheritance Path:
  -- No Super Classes --

Annotations:
  -- No Annotations --
  
// 注意,对象数组的类型文本以[L开头
$ java ClassDeclarationSpy "[Ljava.lang.String;"
Class:
  java.lang.String[]

Modifiers:
  public abstract final

Type Parameters:
  -- No Type Parameters --

Implemented Interfaces:
  interface java.lang.Cloneable
  interface java.io.Serializable

Inheritance Path:
  java.lang.Object

Annotations:
  -- No Annotations --
  
$ java ClassDeclarationSpy java.io.InterruptedIOException
Class:
  java.io.InterruptedIOException

Modifiers:
  public

Type Parameters:
  -- No Type Parameters --

Implemented Interfaces:
  -- No Implemented Interfaces --

Inheritance Path:
  java.io.IOException
  java.lang.Exception
  java.lang.Throwable
  java.lang.Object

Annotations:
  -- No Annotations --

// 注意,该类已经废弃,所以能获取到运行时标注Deprecated
$ java ClassDeclarationSpy java.security.Identity
Class:
  java.security.Identity

Modifiers:
  public abstract

Type Parameters:
  -- No Type Parameters --

Implemented Interfaces:
  interface java.security.Principal
  interface java.io.Serializable

Inheritance Path:
  java.lang.Object

Annotations:
  @java.lang.Deprecated()
  
  

获取类成员信息

常用的API包括获取类的域,方法和构造器对象

获取域的API

  • getDeclaredField()
  • getField()
  • getDeclaredFields()
  • getFields()

获取方法的API

  • getDeclaredMethod()
  • getMethod()
  • getDeclaredMethods()
  • getMethods()

获取构造器的API

  • getDeclaredConstructor()
  • getConstructor()
  • getDeclaredConstructors()
  • getConstructors()

获取嵌套类的API

  • getDeclaredClasses()
  • getClasses()

getDeclared* 的API都是获取类直接声明(包括private)的成员,而get* 的API能获得public的类声明和继承而来的成员

完整代码示例

void printMembers(Member[] mbrs, String s) {
	for (Member mbr : mbrs) {
		if (mbr instanceof Field)
			System.out.format("  %s%n", ((Field)mbr).toGenericString());
	   else if (mbr instanceof Constructor)
			System.out.format("  %s%n", ((Constructor)mbr).toGenericString());
	   else if (mbr instanceof Method)
			System.out.format("  %s%n", ((Method)mbr).toGenericString());
	}
}

private static void printClasses(Class<?> c) {
	Class<?>[] clss = c.getClasses();
	for (Class<?> cls : clss)
		System.out.format("  %s%n", cls.getCanonicalName());
}

域(Field)反射API

域的反射API包括获取域的类型,泛型信息,访问修饰符,获取和修改域的值API

可以通过Class的getFields()和getDeclaredField()来获取域对象

获取域的类型和泛型信息

Field.getType 获取域类型

Field.getGenericType 获取带泛型声明的域类型

完整代码示例

import java.lang.reflect.Field;
import java.util.List;

public class FieldSpy<T> {
	public boolean[][] b = {
		{ false, false }, 
		{ true, true } 
	};
	public String name  = "Alice";
	public List<Integer> list;
	public T val;

	public static void main(String... args) {
		try {
			Class<?> c = Class.forName(args[0]);
			Field f = c.getField(args[1]);
			System.out.format("Type: %s%n", f.getType());
			System.out.format("GenericType: %s%n", f.getGenericType());
	
			// production code should handle these exceptions more gracefully
		} catch (ClassNotFoundException x) {
			x.printStackTrace();
		} catch (NoSuchFieldException x) {
			x.printStackTrace();
		}
	}
}

$ java FieldSpy FieldSpy b
Type: class [[Z
GenericType: class [[Z
$ java FieldSpy FieldSpy name
Type: class java.lang.String
GenericType: class java.lang.String
$ java FieldSpy FieldSpy list
Type: interface java.util.List
GenericType: java.util.List<java.lang.Integer>
$ java FieldSpy FieldSpy val
Type: class java.lang.Object
GenericType: T

获取域的访问修饰符

Field.getModifiers() 获取访问修饰符信息

Field.isSynthetic() 判断域是否是编译器生成的

Field.isEnumCostant() 判断域是否是枚举实例

获取和设置域的值

主要通过以下API

  • Field.get
  • Field.get*
  • Field.set
  • Field.set*

完整代码示例

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));
		
		        // production code should handle these exceptions more gracefully
			} 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

方法(Method)反射API

常用的方法反射API包括:获取方法声明中的类型信息,参数的正式名字,方法的访问修饰符和方法的执行

获取方法的类型信息

Method.getReturnType 获取返回值的类型
Method.getGenericReturnType 获取携带泛型参数返回值的类型

Method.getParameterTypes 获取参数的类型数组
Method.getGenericParameterTypes

Method.getExceptionTypes 获取异常声明的类型数组
Method.getGenericExceptionTypes

Method.isVarArgs() 判断方法是否是可变参数列表

获取方法的参数的正式名字

类编译为.class文件时,参数的名字都会被短名字替换,为了能够用反射获得参数的名字,需要在编译java代码时加上-parameters参数,

Method.getParameters 获取参数Parameter 对象数组

Parameter.getType 获取参数的类型

Parameter.getName 获取参数的名字

Parameter.getModifiers 获取参数的访问修饰符

Parameter.isNamePresent 判断class文件中是否包含参数的正式名字

获取方法的访问修饰符

Method.getModifiers 获取方法的访问修饰符

用Method的反射API来调用方法

Method.invoke 调用方法,传给invoke的第一个参数是一个对象,例如method.invoke(a)相当于非反射调用a.method(),如果调用的静态方法,则参数为invoke的第一个参数null;另外,method.invoke(a, 1, “er”, new int[1]{})相当于a.method(1, “er”, new int[1]{})

完整代码示例

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Locale;
import static java.lang.System.out;
import static java.lang.System.err;

public class Deet<T> {
    private boolean testDeet(Locale l) {
	// getISO3Language() may throw a MissingResourceException
	out.format("Locale = %s, ISO Language Code = %s%n", l.getDisplayName(), l.getISO3Language());
	return true;
    }

    private int testFoo(Locale l) { return 0; }
    private boolean testBar() { return true; }

    public static void main(String... args) {
	if (args.length != 4) {
	    err.format("Usage: java Deet <classname> <langauge> <country> <variant>%n");
	    return;
	}

	try {
	    Class<?> c = Class.forName(args[0]);
	    Object t = c.newInstance();

	    Method[] allMethods = c.getDeclaredMethods();
	    for (Method m : allMethods) {
		String mname = m.getName();
		if (!mname.startsWith("test")
		    || (m.getGenericReturnType() != boolean.class)) {
		    continue;
		}
 		Type[] pType = m.getGenericParameterTypes();
 		if ((pType.length != 1)
		    || Locale.class.isAssignableFrom(pType[0].getClass())) {
 		    continue;
 		}

		out.format("invoking %s()%n", mname);
		try {
		    m.setAccessible(true);
		    Object o = m.invoke(t, new Locale(args[1], args[2], args[3]));
		    out.format("%s() returned %b%n", mname, (Boolean) o);

		// Handle any exceptions thrown by method to be invoked.
		} catch (InvocationTargetException x) {
		    Throwable cause = x.getCause();
		    err.format("invocation of %s failed: %s%n",
			       mname, cause.getMessage());
		}
	    }

        // production code should handle these exceptions more gracefully
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	}
    }
}

测试实例

$ java Deet Deet ja JP JP
invoking testDeet()
Locale = Japanese (Japan,JP), 
ISO Language Code = jpn
testDeet() returned true
$ java Deet Deet xx XX XX
invoking testDeet()
invocation of testDeet failed: 
Couldn't find 3-letter language code for xx

注意可变参数的方法的调用形式稍微有点不同

完整代码示例

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class InvokeMain {
    public static void main(String... args) {
	try {
	    Class<?> c = Class.forName(args[0]);
	    Class[] argTypes = new Class[] { String[].class };
	    Method main = c.getDeclaredMethod("main", argTypes);
  	    String[] mainArgs = Arrays.copyOfRange(args, 1, args.length);
	    System.out.format("invoking %s.main()%n", c.getName());
	    main.invoke(null, (Object)mainArgs);

        // production code should handle these exceptions more gracefully
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	} catch (NoSuchMethodException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (InvocationTargetException x) {
	    x.printStackTrace();
	}
    }
}

测试示例

$ java InvokeMain Deet Deet ja JP JP
invoking Deet.main()
invoking testDeet()
Locale = Japanese (Japan,JP), 
ISO Language Code = jpn
testDeet() returned true

对于签名是参数数目可变的函数,其实只是一种语法糖,最终编译结果只是把参数列表变成一个数组,所以使用Method.invoke的时候要传一个数组Object给invoke

有一点容易让人产生疑惑的是Method的invoke函数签名有新旧两个版本
invoke(Object obj,Object[] args)
invoke(Object obj,Object… args)
数组签名是1.4版本,而可变参数类型是1.5版本,如果没有新版本,那么给多参数的函数传参数就得构造一个Object数组了,但如果不把一个数组转强制换成Object的话,编译器就会指定数组版本,导致参数个数异常;另外,基本类型数组是一个Object类型,因此不需要强制转换

另外,可以通过Method.setAccessible来禁止对方法访问的权限检查

注意方法中的泛型变量都会被擦除到边界例如:void method(T t) 运行时实际上是 void method(Object t)

构造器(Constructors)的反射API

构造器常用的反射API包括:获取构造器声明中的类型信息,构造器的正式名字,构造器的访问修饰符和使用构造器的创建对象

获取构造器声明中的类型信息

Constructor.getParameterTypes 获取参数的类型数组
Constructor.getGenericParameterTypes

Constructor.getExceptionTypes 获取异常声明的类型数组
Constructor.getGenericExceptionTypes

Constructor.isVarArgs() 判断方法是否是可变参数列表

完整代码示例

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import static java.lang.System.out;

public class ConstructorSift {
    public static void main(String... args) {
	try {
	    Class<?> cArg = Class.forName(args[1]);

	    Class<?> c = Class.forName(args[0]);
	    Constructor[] allConstructors = c.getDeclaredConstructors();
	    for (Constructor ctor : allConstructors) {
		Class<?>[] pType  = ctor.getParameterTypes();
		for (int i = 0; i < pType.length; i++) {
		    if (pType[i].equals(cArg)) {
			out.format("%s%n", ctor.toGenericString());

			Type[] gpType = ctor.getGenericParameterTypes();
			for (int j = 0; j < gpType.length; j++) {
			    char ch = (pType[j].equals(cArg) ? '*' : ' ');
			    out.format("%7c%s[%d]: %s%n", ch,
				       "GenericParameterType", j, gpType[j]);
			}
			break;
		    }
		}
	    }

        // production code should handle this exception more gracefully
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}

测试示例输出

$ java ConstructorSift java.util.Formatter java.util.Locale
public
java.util.Formatter(java.io.OutputStream,java.lang.String,java.util.Locale)
throws java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.io.OutputStream
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
public java.util.Formatter(java.lang.String,java.lang.String,java.util.Locale)
throws java.io.FileNotFoundException,java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.lang.String
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
public java.util.Formatter(java.lang.Appendable,java.util.Locale)
       GenericParameterType[0]: interface java.lang.Appendable
      *GenericParameterType[1]: class java.util.Locale
public java.util.Formatter(java.util.Locale)
      *GenericParameterType[0]: class java.util.Locale
public java.util.Formatter(java.io.File,java.lang.String,java.util.Locale)
throws java.io.FileNotFoundException,java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.io.File
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale

$ java ConstructorSift java.lang.String "[C"
java.lang.String(int,int,char[])
       GenericParameterType[0]: int
       GenericParameterType[1]: int
      *GenericParameterType[2]: class [C
public java.lang.String(char[],int,int)
      *GenericParameterType[0]: class [C
       GenericParameterType[1]: int
       GenericParameterType[2]: int
public java.lang.String(char[])
      *GenericParameterType[0]: class [C
      
$ java ConstructorSift java.lang.ProcessBuilder "[Ljava.lang.String;"
public java.lang.ProcessBuilder(java.lang.String[])
      *GenericParameterType[0]: class [Ljava.lang.String;


获取构造器的访问修饰符

Constructor.getModifiers

创建对象

Constructor.newInstance 创建一个对象

Class.newInstance和Constructor.newInstance反射API都能创建一个对象,但前者只能调用不带参数的构造器,且要满足访问修饰符的约束;通过修改访问权限可以使用Constructor.newInstance访问private的构造函数

完整代码示例

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static java.lang.System.out;

class EmailAliases {
    private Set<String> aliases;
    private EmailAliases(HashMap<String, String> h) {
	aliases = h.keySet();
    }

    public void printKeys() {
	out.format("Mail keys:%n");
	for (String k : aliases)
	    out.format("  %s%n", k);
    }
}

public class RestoreAliases {

    private static Map<String, String> defaultAliases = new HashMap<String, String>();
    static {
	defaultAliases.put("Duke", "duke@i-love-java");
	defaultAliases.put("Fang", "fang@evil-jealous-twin");
    }

    public static void main(String... args) {
	try {
	    Constructor ctor = EmailAliases.class.getDeclaredConstructor(HashMap.class);
	    ctor.setAccessible(true);
	    EmailAliases email = (EmailAliases)ctor.newInstance(defaultAliases);
	    email.printKeys();

        // production code should handle these exceptions more gracefully
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (InvocationTargetException x) {
	    x.printStackTrace();
	} catch (NoSuchMethodException x) {
	    x.printStackTrace();
	}
    }
}

测试示例

$ java RestoreAliases
Mail keys:
  Duke
  Fang
  

数组(Array)反射API

常用的数组反射API包括:获取数组的类型,数组元素的类型,创建数组,获取和设置数组元素

获取数组和数组元素的类型

Class.isArray 判断一个对象是否为数组
Class.getComponentType 获取数组的元素的类型

完整代码示例

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import static java.lang.System.out;

public class ArrayFind {
    public static void main(String... args) {
	boolean found = false;
 	try {
	    Class<?> cls = Class.forName(args[0]);
	    Field[] flds = cls.getDeclaredFields();
	    for (Field f : flds) {
 		Class<?> c = f.getType();
		if (c.isArray()) {
		    found = true;
		    out.format("%s%n"
                               + "           Field: %s%n"
			       + "            Type: %s%n"
			       + "  Component Type: %s%n",
			       f, f.getName(), c, c.getComponentType());
		}
	    }
	    if (!found) {
		out.format("No array fields%n");
	    }

        // production code should handle this exception more gracefully
 	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}

测试示例

$ java ArrayFind java.lang.Throwable
private java.lang.StackTraceElement[] java.lang.Throwable.stackTrace
           Field: stackTrace
            Type: class [Ljava.lang.StackTraceElement;
  Component Type: class java.lang.StackTraceElement
  

创建数组

Array.newInstance 创建多维数组

完整代码示例

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.Arrays;
import static java.lang.System.out;

public class ArrayCreator {
    private static String s = "java.math.BigInteger bi[] = { 123, 234, 345 }";
    private static Pattern p = Pattern.compile("^\\s*(\\S+)\\s*\\w+\\[\\].*\\{\\s*([^}]+)\\s*\\}");

    public static void main(String... args) {
        Matcher m = p.matcher(s);

        if (m.find()) {
            String cName = m.group(1);
            String[] cVals = m.group(2).split("[\\s,]+");
            int n = cVals.length;

            try {
                Class<?> c = Class.forName(cName);
                Object o = Array.newInstance(c, n);
                for (int i = 0; i < n; i++) {
                    String v = cVals[i];
                    Constructor ctor = c.getConstructor(String.class);
                    Object val = ctor.newInstance(v);
                    Array.set(o, i, val);
                }

                Object[] oo = (Object[])o;
                out.format("%s[] = %s%n", cName, Arrays.toString(oo));

            // production code should handle these exceptions more gracefully
            } catch (ClassNotFoundException x) {
                x.printStackTrace();
            } catch (NoSuchMethodException x) {
                x.printStackTrace();
            } catch (IllegalAccessException x) {
                x.printStackTrace();
            } catch (InstantiationException x) {
                x.printStackTrace();
            } catch (InvocationTargetException x) {
                x.printStackTrace();
            }
        }
    }
}
$ java ArrayCreator
java.math.BigInteger [] = [123, 234, 345]

获取和设置数组元素

Array.set* 设置基本元素
Array.get* 获取基本元素
Array.set 设置引用元素
Array.get 获取引用元素

完整代码示例

import java.lang.reflect.Array;
import static java.lang.System.out;

public class CreateMatrix {
    public static void main(String... args) {
        Object matrix = Array.newInstance(int.class, 2, 2);
        Object row0 = Array.get(matrix, 0);
        Object row1 = Array.get(matrix, 1);

        Array.setInt(row0, 0, 1);
        Array.setInt(row0, 1, 2);
        Array.setInt(row1, 0, 3);
        Array.setInt(row1, 1, 4);

        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                out.format("matrix[%d][%d] = %d%n", i, j, ((int[][])matrix)[i][j]);
    }
}

$ java CreateMatrix
matrix[0][0] = 1
matrix[0][1] = 2
matrix[1][0] = 3
matrix[1][1] = 4

枚举(Enum)反射API

常用枚举反射API包括

Class.isEnum 判断类型是否为枚举
Class.getEnumConstants 获取一个枚举类型的所有枚举值
Field.isEnumConstant 判断一个域是否为枚举常量

完整代码示例

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

enum Eon { HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC }

public class EnumConstants {
    public static void main(String... args) {
	try {
	    Class<?> c = (args.length == 0 ? Eon.class : Class.forName(args[0]));
	    out.format("Enum name:  %s%nEnum constants:  %s%n",
		       c.getName(), Arrays.asList(c.getEnumConstants()));
	    if (c == Eon.class)
		out.format("  Eon.values():  %s%n",
			   Arrays.asList(Eon.values()));

        // production code should handle this exception more gracefully
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}

测试示例

$ java EnumConstants java.lang.annotation.RetentionPolicy
Enum name:  java.lang.annotation.RetentionPolicy
Enum constants:  [SOURCE, CLASS, RUNTIME]
$ java EnumConstants java.util.concurrent.TimeUnit
Enum name:  java.util.concurrent.TimeUnit
Enum constants:  [NANOSECONDS, MICROSECONDS, 
                  MILLISECONDS, SECONDS, 
                  MINUTES, HOURS, DAYS]

参考文献

The Reflection API