反射库提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序。
目录
1、Class对象
1.1 是什么
在程序运行期间,Java运行时系统为所有的对象维护一个被称作运行时的类型标识。这个信息追踪着每个对象所属的类。而此时,可以通过专门的类访问这些信息,保存这些信息的类称为Class。换句话说,在程序运行期间,我们在代码定义的每一个类都会对应一个Class对象,该对象保存了这个类的所有信息,其中包括类名、父类、实现的接口、属性、方法、构造方法等。
需要注意,一个Class对象实际上表示的是一种类型,而这个类型未必一定是累,也可以是int等原始类型。
1.2如何获取Class对象
获取Class对象有三种方式:
- Class.forName(),例:
Class c = Class.forName("java.util.List");
- 类名.class,例:
Class c = Random.class
- 对象.getClass(),例:
Random r = new Random(); Class c = r.getClass();
2、反射常用API
2.1 Class中常用API
上边我们知道Class对象保存的是java类运行时信息,因此Class中的API就是获取、修改java类的运行时信息
- 关于类本身信息的api
//=================Class对象中的方法======================
//获取类名(全路径类名)
public String getName()
//获取父类
public native Class<? super T> getSuperclass();
//获取实现的接口
public Class<?>[] getInterfaces()
//判断类型是否为原始类型:java.lang.Boolean#TYPE,java.lang.Character#TYPE,java.lang.Byte#TYPE,java.lang.Short#TYPE,java.lang.Integer#TYPE,java.lang.Long#TYPE,java.lang.Float#TYPE,java.lang.Double#TYPE,java.lang.Void#TYPE
public native boolean isPrimitive();
- 类中字段
类中的字段在Class对象中对应一个Field对象
//=================Class对象中的方法======================
//根据字段名获取字段
public Field getField(String name)
//获取类中所有共有字段,包括父类
public Field[] getFields() throws SecurityException
//获取本类中所有字段
public Field[] getDeclaredFields() throws SecurityException
//=================Field对象中的方法======================
//获取字段类型
public Class<?> getType()
//获取字段名称
public String getName()
//获取某个对象中某个字段的值(obj为拥有字段的某个对象)
public Object get(Object obj)
throws IllegalArgumentException, IllegalAccessException
//给某个对象的某个字段设置值
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
- 类的构造函数
类中的构造方法在Class对象中对应一个Constructor对象
//=================Class对象中的方法======================
//调用默认构造函数创建创建对象
public T newInstance()
throws InstantiationException, IllegalAccessException
//根据参数获取构造函数
public Constructor<T> getConstructor(Class<?>... parameterTypes)
//获取类中所有的共有构造器
public Constructor<?>[] getConstructors() throws SecurityException
//获取本类中所有构造器(包括私有构造函数)
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
//=================Constructor对象中的方法======================
//调用构造函数创建对象
public T newInstance(Object ... initargs)
- 类中普通方法
类中的普通方法在Class对象中对应一个Method对象
//=================Class对象中的方法======================
//根据方法名称获取方法对象
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
//获取类中所有共有方法(包括父类中的)
public Method[] getMethods() throws SecurityException
//获取类中所有方法(包括私有成员)
public Method[] getDeclaredMethods() throws SecurityException
//=================Method对象中的方法======================
//获取方法名
public String getName()
//获取方法返回类型
public Class<?> getReturnType()
//获取参数
public Parameter[] getParameters()
//调用方法
public Object invoke(Object obj, Object... args)
- 公共API
//获取方法、类、字段修饰符整数
public int getModifiers()
//转换String
Modifier.toString(modifiers)//注:int modifiers = med.getModifiers();
//设置私有成员的反射访问权限
AccessibleObject.setAccessible(declaredFields,true);//注:Field[] declaredFields = objClass.getDeclaredFields();
public void setAccessible(boolean flag)
2.2 反射中关于数组操作的API
//判断是否是数组:Class类中
public native boolean isArray();
//获取数组元素的类型:Class类中
public native Class<?> getComponentType();
//创建数组
Array.newInstancenewInstance(Class<?> componentType, int length)
//获取数组长度
public static native int getLength(Object array)
throws IllegalArgumentException;
上面介绍了反射的基本API,其实除了上述的这些常用的API,反射中关于注解的API也很常用。
3、反射的作用
反射机制可以用来:
- 在运行时分析类;
- 在运行时查看对象,例如编写一个所有对象(包括数组)和非对象(基本类型)都可以使用的toString方法;
- 实现通用的数组操作代码;
- 利用Method对象实现类似C++指针的功能 。
上述四个作用我们分别用四个案例说明。
例一:在运行时分析类,打印一个类的所有信息
public class Reflection01 {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
Class<Double> doubleClass = Double.class;
//获取类修饰符
int modifiers = doubleClass.getModifiers();
String cd = Modifier.toString(modifiers);
sb.append(cd + " ");
//获取类名
String className = doubleClass.getName();
sb.append(className + " ");
//获取继承的类
Class<? super Double> superclass = doubleClass.getSuperclass();
if (superclass!=null) {
sb.append("extend "+superclass.getName()+" ");
}
Class<?>[] interfaces = doubleClass.getInterfaces();
//获取实现的接口
if (interfaces.length>0){
sb.append("implements ");
for (Class<?> anInterface : interfaces) {
sb.append(anInterface.getName()+" ");
}
}
sb.append("\n{");
System.out.print(sb);
printConstructors(doubleClass);
System.out.println();
printFields(doubleClass);
System.out.println();
printMethods(doubleClass);
System.out.println("}");
}
//打印构造方法
public static void printConstructors(Class c) {
//获取类中所有的构造方法(私有的和公有的)
Constructor[] constructor = c.getDeclaredConstructors();
for (Constructor cons : constructor) {
StringBuffer sb = new StringBuffer();
sb.append("\t");
//获取修饰符
int modifiers = cons.getModifiers();
String d = Modifier.toString(modifiers);
sb.append(d+" ");
//获取参数方法名
sb.append(cons.getName()+"(");
//获取参数
Parameter[] parameters = cons.getParameters();
if (parameters.length>0){
for (int i = 0; i < parameters.length; i++) {
Class<?> type = parameters[i].getType();
String cName = type.getName();
sb.append(cName);
if (i<parameters.length-1){
sb.append(", ");
}
}
}
sb.append(");");
System.out.println(sb);
}
}
//打印属性
public static void printMethods(Class c) {
//获取类中的共有方法(包括父类中的共有方法)
Method[] methods = c.getMethods();
for (Method med : methods) {
StringBuffer sb = new StringBuffer();
sb.append("\t");
//获取修饰符
int modifiers = med.getModifiers();
String d = Modifier.toString(modifiers);
sb.append(d+" ");
//获取返回类型
Class<?> returnType = med.getReturnType();
sb.append(returnType.getName()+" ");
//获取参数方法名
sb.append(med.getName()+"(");
//获取参数
Parameter[] parameters = med.getParameters();
if (parameters.length>0){
for (int i = 0; i < parameters.length; i++) {
Class<?> type = parameters[i].getType();
String cName = type.getName();
sb.append(cName);
if (i<parameters.length-1){
sb.append(", ");
}
}
}
sb.append(");");
System.out.println(sb);
}
}
//打印普通方法
public static void printFields(Class c) {
Field[] fields = c.getFields();
for (Field field : fields) {
StringBuffer sb = new StringBuffer("\t");
//获取修饰符
int modifiers = field.getModifiers();
String d = Modifier.toString(modifiers);
sb.append(d+" ");
//获取字段类型
Class<?> type = field.getType();
sb.append(type.getName()+" ");
//获取字段名
sb.append(field.getName()+";");
System.out.println(sb);
}
//获取父类*有方法
Class superclass = c.getSuperclass();
if (superclass!=null){
printFields(superclass);
}
}
}
输出:========>
public final java.lang.Double extend java.lang.Number implements java.lang.Comparable
{ public java.lang.Double(double);
public java.lang.Double(java.lang.String);
public static final double POSITIVE_INFINITY;
public static final double NEGATIVE_INFINITY;
public static final double NaN;
public static final double MAX_VALUE;
public static final double MIN_NORMAL;
public static final double MIN_VALUE;
public static final int MAX_EXPONENT;
public static final int MIN_EXPONENT;
public static final int SIZE;
public static final int BYTES;
public static final java.lang.Class TYPE;
public boolean equals(java.lang.Object);
public static java.lang.String toString(double);
public java.lang.String toString();
public int hashCode();
public static int hashCode(double);
public static double min(double, double);
public static double max(double, double);
public static native long doubleToRawLongBits(double);
public static long doubleToLongBits(double);
public static native double longBitsToDouble(long);
public volatile int compareTo(java.lang.Object);
public int compareTo(java.lang.Double);
public byte byteValue();
public short shortValue();
public int intValue();
public long longValue();
public float floatValue();
public double doubleValue();
public static java.lang.Double valueOf(java.lang.String);
public static java.lang.Double valueOf(double);
public static java.lang.String toHexString(double);
public static int compare(double, double);
public static boolean isNaN(double);
public boolean isNaN();
public static boolean isInfinite(double);
public boolean isInfinite();
public static boolean isFinite(double);
public static double sum(double, double);
public static double parseDouble(java.lang.String);
public final void wait(long, int);
public final native void wait(long);
public final void wait();
public final native java.lang.Class getClass();
public final native void notify();
public final native void notifyAll();
}
例二:通用toString方法
public class Reflection02 {
public static void main(String[] args) throws IllegalAccessException {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(11);
list.add(111);
System.out.println(new Reflection02().toString(list));
}
private static List<Object> visited = new ArrayList<>();
public String toString(Object obj) throws IllegalAccessException {
if (obj==null)
return null;
if (visited.contains(obj))
return "...";
visited.add(obj);
Class<?> objClass = obj.getClass();
if (objClass.isArray()){
//获取数组类型
StringBuffer sb = new StringBuffer();
String s = objClass.getComponentType() + "[]{";
sb.append(s);
//遍历数组元素
for (int i = 0; i < Array.getLength(obj); i++) {
if (i>0){
sb.append(",");
}
Object val = Array.get(obj, i);
if (objClass.getComponentType().isPrimitive())
sb.append(val);
else
sb.append(toString(val));
}
sb.append("}");
return sb.toString();
}
String className = objClass.getName();
StringBuffer sb = new StringBuffer(className);
do {
sb.append("[");
Field[] declaredFields = objClass.getDeclaredFields();
AccessibleObject.setAccessible(declaredFields,true);
for (Field field : declaredFields) {
if (!Modifier.isStatic(field.getModifiers())){
if (!sb.toString().endsWith("[")){
sb.append(",");
}
sb.append(field.getName()+"=");
Object val = field.get(obj);
Class<?> fieldType = field.getType();
if (fieldType.isPrimitive()){
sb.append(val);
}else {
sb.append(toString(val));
}
}
}
sb.append("]");
objClass = objClass.getSuperclass();
}while (objClass!=null);
return sb.toString();
}
}
输出:==========>
java.util.ArrayList[elementData=class java.lang.Object[]{java.lang.Integer[value=1][][],java.lang.Integer[value=11][][],java.lang.Integer[value=111][][],null,null,null,null,null,null,null},size=3][modCount=3][][]
例三:实现数组扩容
public class Reflection03 {
public static void main(String[] args) {
int[] arr = {1,1,11,22,12,21,2};
int[] newArr = (int[]) new Reflection03().copyArray(arr, 10);
System.out.println(newArr.length);
System.out.println(Arrays.toString(arr));
}
/**
* 复制数组到指定长度的新数组
* @param obj
* @param length
* @return
*/
public Object copyArray(Object obj,int length){
Class<?> objClass = obj.getClass();
if(!objClass.isArray()) return null;
Class<?> componentType = objClass.getComponentType();
int objLength = Array.getLength(obj);
Object arr = Array.newInstance(componentType, length);
System.arraycopy(obj,0,arr,0,Math.min(objLength,length));
return arr;
}
}
输出:=============>
10
[1, 1, 11, 22, 12, 21, 2]
例四:通过Method的invoke方法执行某个类中的某个方法
public class Reflection04 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method sqrt = Math.class.getMethod("sqrt", double.class);
Object val = sqrt.invoke(null, 36);
System.out.println(val);
}
}
输出:====================> 6.0
参考:《Java核心卷》卷1 ,5.7反射