java反射基础知识总结

反射定义

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
欲用反射,必先得字节码(.class文件对象)。

先来看看java反射的三个阶段:

源文件阶段 字节码阶段 创建对象阶段 String.java文件 javac命令编译 Class c = Class.forName("java.lang.String") java命令运行 Class c = String.class String s = new String() Class c = s.getClass() 源文件阶段 字节码阶段 创建对象阶段

每一个阶段我们都有对应的手段得到字节码文件对象,得到对应的字节码文件对象只是我们反射的第一步,我们真正想做的是改变成员变量的属性值或者是调用类中的方法。
要想改变属性或者方法必须得有对象可行,下面先介绍如何通过反射创建对象:

反射创建对象

Class c = String.class;
String s = (String) c.newInstance();

一个字节码文件对象调用该方法可以创建其实例对象,注意此种创建对象方式只能局限于非私有空参构造方法(没有空参构造或者空参构造是私有的不能通过此种方法创建对象)。

Constructor<T>      getConstructor(Class<?>... parameterTypes)//根据指定构造参数类型得到对应的Constructor对象
Constructor<?>[]    getConstructors()//得到包含该类所有public构造方法Constructor对象的数组

上面的一组方法可以得到public权限修饰的构造方法

Constructor<T>      getDeclaredConstructor(Class<?>... parameterTypes)
Constructor<?>[]    getDeclaredConstructors() 

在Class类中有一类方法是以getDeclared…开头的,这一类方法可以得到类中私有的构造、属性和方法。
为了便于举例说明,这里我们创建一个自定义的测试类:

package com.qj.reflect;
public class ReflectBean {
	private ReflectBean() {
		super();//私有构造
	}

	public void print(String s) {
		System.out.println(s);
	}
}

该类私有了构造方法,下面通过反射创建对象并调用该类中的方法:

public static void testConstructor() throws Exception {
	Class c = Class.forName("com.qj.reflect.ReflectBean");
	Constructor dc = c.getDeclaredConstructor();//得到私有构造
	dc.setAccessible(true);// 解除私有权限
	ReflectBean rb = (ReflectBean) dc.newInstance();//创建对象
	rb.print("反射创建对象调用方法");
}

反射修改属性值

与获取字节码对象的构造方法类似,获取成员属性Class类中也有对应的API:

Field      getField(String name)//根据属性名称获取Field对象,仅限public
Field[]    getFields()//获取该类所有的public属性
Field      getDeclaredField(String name)//根据属性名称获取Field对象,private属性也可获取
Field[]    getDeclaredFields()//获取该类所有的属性

为了便于演示我们在ReflectBean类中添加一个属性flag

private boolean flag = true;

反射修改属性值:

public static void testField() throws Exception {
	Class c = Class.forName("com.qj.reflect.ReflectBean");
	Constructor dc = c.getDeclaredConstructor();// 得到私有构造
	dc.setAccessible(true);// 解除私有权限
	ReflectBean rb = (ReflectBean) dc.newInstance();// 创建对象
	Field flag = c.getDeclaredField("flag");//通过属性flag得到对应的Field对象
	flag.setAccessible(true);// 解除私有权限
	flag.setBoolean(rb, false);//修改属性值
}

Field类中修改属性值API:

set(Object obj, Object value)
setBoolean(Object obj, boolean z)
setByte(Object obj, byte b)
setChar(Object obj, char c)
setDouble(Object obj, double d)
setFloat(Object obj, float f)
setInt(Object obj, int i)
setLong(Object obj, long l)
setShort(Object obj, short s)

反射调用方法

在开发中经常遇到有某个类的对象但是方法是私有的,眼巴巴地看着不能调用,反射的强大之处就是能够让你为所欲为!

Method      getMethod(String name, Class<?>... parameterTypes)
Method[]    getMethods()
Method      getDeclaredMethod(String name, Class<?>... parameterTypes) 
Method[]    getDeclaredMethods() 

结合之前对于构造方法和属性的获取,Class类中对方法对象的获取就很容易理解了。
为了演示反射调用方法,我们在ReflectBean中添加一个私有的方法

private void secret() {
	System.out.println("私有方法被调用了!");
}

利用反射调用私有方法:

public static void testMethod() throws Exception{
	Class c = Class.forName("com.qj.reflect.ReflectBean");
	Constructor dc = c.getDeclaredConstructor();// 得到私有构造
	dc.setAccessible(true);// 解除私有权限
	ReflectBean rb = (ReflectBean) dc.newInstance();// 创建对象
	Method dm = c.getDeclaredMethod("secret");//根据方法名称获取Method对象
	dm.setAccessible(true);// 解除私有权限
	dm.invoke(rb);//调用方法
}

我们向ReflectBean测试类中添加一个有参的私有方法:

private void secret(String s) {
	System.out.println("有参私有方法被调用了!  s : " + s);
}

反射调用有参私有方法:

//Class c , ReflectBean rb 生成步骤略
Method dm = c.getDeclaredMethod("secret", String.class);// 根据方法名称及方法参数类型获取Method对象
dm.setAccessible(true);// 解除私有权限
dm.invoke(rb, "方法参数内容");// 调用方法

众所周知,我们利用反射无非是为了获取、改变对象的属性或者调用对象的方法,下面总结一个反射的工具类,让我们使用反射易如反掌!

反射工具类

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectUtil {
    private ReflectUtil() {
        super();
    }

    /**
     * 根据全类名得到一个该类的对象(仅限非私有空参构造)
     *
     * @param className 全类名(形如com.qj.reflect.ReflectBean,内部类需要$拼接)
     * @return 该类的实例
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public static Object newInstance(String className)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        Class c = Class.forName(className);
        return c.newInstance();
    }

    /**
     * 根据全类名以及构造方法参数得到一个该类的对象
     *
     * @param className 全类名(形如com.qj.reflect.ReflectBean,内部类需要$拼接)
     * @param args      构造方法参数(可变参数)
     * @return 该类的实例
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws SecurityException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     */
    public static Object createInstance(String className, Object... args)
            throws ClassNotFoundException, NoSuchMethodException,
            SecurityException, InstantiationException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {
        Class c = Class.forName(className);
        Constructor dc;
        int length = args.length;
        if (args != null && length > 0) {//有参构造
            Class[] type = new Class[length];
            for (int i = 0; i < length; i++) {
                type[i] = args[i].getClass();
            }
            dc = c.getDeclaredConstructor(type);
            dc.setAccessible(true);
            return dc.newInstance(args);
        }
        dc = c.getDeclaredConstructor();//无参构造
        dc.setAccessible(true);
        return dc.newInstance();
    }

    /**
     * 根据传过来的对象以及对象的属性名称更改属性值
     *
     * @param obj       该类的实例
     * @param fieldName 该类的属性名称
     * @param value     要更改的属性值
     * @throws NoSuchFieldException
     * @throws SecurityException
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static void modfyField(Object obj, String fieldName, Object value)
            throws NoSuchFieldException, SecurityException,
            IllegalArgumentException, IllegalAccessException {
        Class<?> c = obj.getClass();
        Field field = c.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    /**
     * 获取类的静态属性(仅限静态属性,非静态属性报错)
     *
     * @param className 全类名(形如com.qj.reflect.ReflectBean,内部类需要$拼接)
     * @param fieldName 类的静态属性名称
     * @return 该类的静态属性 {@code fieldName} 的值
     * @throws ClassNotFoundException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static Object getStaticField(String className, String fieldName)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = Class.forName(className);
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(null);
    }

    /**
     * 获取类的属性(静态属性、非静态属性均可)
     *
     * @param className 全类名(形如com.qj.reflect.ReflectBean,内部类需要$拼接)
     * @param obj       该类的实例对象
     * @param fieldName 类的属性名称
     * @return 该类的属性 {@code fieldName} 的值
     * @throws ClassNotFoundException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static Object getField(String className, Object obj, String fieldName)
            throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        Class<?> clazz = Class.forName(className);
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(obj);
    }

    /**
     * 根据传过来的对象以及对象的方法名称调用该方法
     *
     * @param obj        该类的实例
     * @param methodName 要调用的方法
     * @param args       方法的参数(可变参数)
     * @throws NoSuchMethodException
     * @throws SecurityException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     */
    public static void invokeMethod(Object obj, String methodName,
                                    Object... args) throws NoSuchMethodException, SecurityException,
            IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        Class c = obj.getClass();
        Method method;
        if (args != null && args.length > 0) {// 有参方法
            Class[] type = new Class[args.length];
            for (int i = 0; i < type.length; i++) {
                type[i] = args[i].getClass();
            }
            method = c.getDeclaredMethod(methodName, type);
        } else {// 空参方法
            method = c.getDeclaredMethod(methodName);
        }
        method.setAccessible(true);
        method.invoke(obj, args);
    }
}

有了这个工具类我们用反射就很easy了:

ReflectBean obj = (ReflectBean) ReflectUtil
.createInstance("com.qj.reflect.ReflectBean");//创建对象
ReflectUtil.modfyField(obj, "flag", false);// 修改flag属性值
ReflectUtil.invokeMethod(obj, "secret");// 调用secret空参构造
ReflectUtil.invokeMethod(obj, "secret", "太帅了");// 调用secret有参构造

通过使用反射工具类大大减少了代码量,一句代码解决一个问题,清晰明朗。

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值