目录
反射库提供了丰富的工具集,以便编写能动态操纵Java代码的程序(JavaBean中即大量应用)。通过反射,可以知道任意类的所有属性和方法,调用对象的属性和方法。反射机制可以:
- 在运行时分析类的能力;
- 在运行时查看对象;
- 实现通用的数组操作代码;
- 利用Method对象:调用函数;
反射操作类
java.lang.reflect
包中封装了反射相关的操作类:
- Class:类的实体;
- Field:类的成员变量(属性);
- Method:类的方法;
- Constructor:类的构造方法;
Class类
Class类代表类的实体,在运行的应用程序中表示类和接口。一些重要方法:
- getClassLoader():获取类的加载器;
- getClasses():获取类中包含的所有公共类和接口;
- getDeclaredClasses():获取类中包含的所有类和接口;
- forName(String className):根据类名返回类对象;
- getName():返回类的完整名(getSimpleName:仅类名,不包括包名);
- newInstance():创建类实例;
- getPackage():获取包名;
- getSuperClass():获取当前类的父类;
- getInterfaces():获取当前类实现的类或接口;
- get[Declared]Fields:获取公开/全部属性;
- get[Declared]Constructors:获取公开/全部构造方法
- get[Declared]Methods:获取公开/全部方法
对于数组(使用isArray判断),getName返回的是内部定义的类型(不易识别),此时需要通过getComponentType
来获取数组元素对应类型。
属性类
Field类代表类的属性:
- get(Object obj):获取obj对象中对应属性值;
- set(Object obj, Object value):设定obj对象中对应属性值;
默认属性是不允许随意操作,需要通过AccessibleObject.setAccessible(fields, true)
设定允许后才可以get/set。
方法类
Method代表类的方法,通过invoke来调用对应方法;
Constructor代表构造方法,通过newInstance调用对应构造方法;
反射示例
对象分析
获取对象内属性的值,为避免对象内出现循环引用,增加一个链表记录已访问过的属性。
static String ObjectAnalyzer(Object obj) {
List<Object> lstVisisted = new ArrayList<>();
return ObjectAnalyzer(obj, lstVisisted);
}
static String ObjectAnalyzer(Object obj, List<Object> visited) {
if (obj == null)
return "null";
if (visited.contains(obj))
return "...";
visited.add(obj);
Class<?> cl = obj.getClass();
if (cl == String.class)
return (String) obj;
if (cl.isArray()) {
String r = cl.getComponentType() + "[]{";
for (int i = 0; i < Array.getLength(obj); i++) {
if (i > 0)
r += ", ";
Object val = Array.get(obj, i);
if (cl.getComponentType().isPrimitive())
r += val;
else
r += ObjectAnalyzer(val, visited);
}
return r + "}";
}
String r = cl.getName();
// inspect the fields of this class and all superclasses
do {
r += "{";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
// get the names and values of all fields
for (Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())) {
if (!r.endsWith("{"))
r += ", ";
r += f.getName() + "=";
try {
Class<?> t = f.getType();
Object val = f.get(obj);
if (t.isPrimitive())
r += val;
else
r += ObjectAnalyzer(val, visited);
} catch (Exception e) {
e.printStackTrace();
}
}
}
if (r.endsWith("{"))
r = r.substring(0, r.length() - 1);
else
r += "}";
cl = cl.getSuperclass();
} while (cl != null);
return r;
}
如我们分析一个日期时间对象,会返回其属性(若为对象类型则显示其对象类名)与对应值:
ObjectAnalyzer(LocalDateTime.now())
// java.time.LocalDateTime{date=java.time.LocalDate{year=2020, month=3, day=19}, time=java.time.LocalTime{hour=22, minute=59, second=25, nano=517000000}}
类定义
通过反射类,获取类的定义信息(构造方法、属性和方法):
- 嵌套类与父类之间使用
$
分割:类似Outer$Nested
; - 数组需要特殊处理:
int[]
默认返回[I
类型;
private static void ClassReflection(String name) {
try {
// print class name and superclass name (if != Object)
Class<?> cl = Class.forName(name);
Class<?> supercl = cl.getSuperclass();
String modifiers = Modifier.toString(cl.getModifiers());
if (modifiers.length() > 0)
System.out.print(modifiers + " ");
System.out.print("class " + name);
if (supercl != null && supercl != Object.class)
System.out.print(" extends " + supercl.getName());
System.out.print("\n{\n");
printConstructors(cl);
System.out.println();
printMethods(cl);
System.out.println();
printFields(cl);
System.out.println("}");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void printConstructors(Class<?> cl) {
Constructor<?>[] constructors = cl.getDeclaredConstructors();
for (Constructor<?> c : constructors) {
String name = c.getName();
System.out.print(Indent_Blank);
String modifiers = Modifier.toString(c.getModifiers());
if (modifiers.length() > 0)
System.out.print(modifiers + " ");
System.out.print(name + "(");
// print parameter types
Class<?>[] paramTypes = c.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(getRealTypeName(paramTypes[j]));
}
System.out.println(");");
}
}
public static void printMethods(Class<?> cl) {
Method[] methods = cl.getDeclaredMethods();
for (Method m : methods) {
Class<?> retType = m.getReturnType();
String name = m.getName();
System.out.print(Indent_Blank);
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0)
System.out.print(modifiers + " ");
System.out.print(getRealTypeName(retType) + " " + name + "(");
Class<?>[] paramTypes = m.getParameterTypes();
for (int j = 0; j < paramTypes.length; j++) {
if (j > 0)
System.out.print(", ");
System.out.print(getRealTypeName(paramTypes[j]));
}
System.out.println(");");
}
}
public static void printFields(Class<?> cl) {
Field[] fields = cl.getDeclaredFields();
for (Field f : fields) {
Class<?> type = f.getType();
String typeName = getRealTypeName(type);
System.out.print(Indent_Blank);
String modifiers = Modifier.toString(f.getModifiers());
if (modifiers.length() > 0)
System.out.print(modifiers + " ");
System.out.println(typeName + " " + f.getName() + ";");
}
}
private static String getRealTypeName(Class<?> type) {
String typeName;
if (type.isArray()) {
typeName = type.getComponentType().getName() + "[]";
} else {
typeName = type.getName();
}
return typeName;
}
数组Copy
为了复制数组我们需要先获取数组的真实类型与长度(通过Array类获取)。
static Object ArrayCopyOf(Object ary, int newLength) {
Class<?> cl = ary.getClass();
if (!cl.isArray())
return null;
Class<?> componentType = cl.getComponentType();
int length = Array.getLength(ary);
Object newArray = Array.newInstance(componentType, newLength);
System.arraycopy(ary, 0, newArray, 0, Math.min(length, newLength));
return newArray;
}