- 类(Class)反射API
- 域(Field)反射API
- 方法(Method)反射API
- 构造器(Constructors)的反射API
- 数组(Array)反射API
- 枚举(Enum)反射API
- 参考文献
本文是对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]