java反射入门及其使用案例

反射库提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵java代码的程序。

目录

1、Class对象

1.1 是什么

在程序运行期间,Java运行时系统为所有的对象维护一个被称作运行时的类型标识。这个信息追踪着每个对象所属的类。而此时,可以通过专门的类访问这些信息,保存这些信息的类称为Class。换句话说,在程序运行期间,我们在代码定义的每一个类都会对应一个Class对象,该对象保存了这个类的所有信息,其中包括类名、父类、实现的接口、属性、方法、构造方法等。
需要注意,一个Class对象实际上表示的是一种类型,而这个类型未必一定是累,也可以是int等原始类型。

1.2如何获取Class对象

获取Class对象有三种方式:

  1. Class.forName(),例: Class c = Class.forName("java.util.List");
  2. 类名.class,例: Class c = Random.class
  3. 对象.getClass(),例: Random r = new Random(); Class c = r.getClass();

2、反射常用API

2.1 Class中常用API
上边我们知道Class对象保存的是java类运行时信息,因此Class中的API就是获取、修改java类的运行时信息

  1. 关于类本身信息的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();

  1. 类中字段
    类中的字段在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
  1. 类的构造函数
    类中的构造方法在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)
  1. 类中普通方法
    类中的普通方法在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)
  1. 公共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反射

上一篇:TCXGRID控件常用属性介绍


下一篇:文档处理—内部插入