反射
概念
Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。
反射需要使用的API
获取字节码对象
Class.forName(“类的全路径”);
类名.class
对象.getClass();
常用方法
package cn.tedu.reflection;import org.junit.Test;/*** 测试反射技术*/public class TestReflect {/*单元测试:是java运行测试的最小单位,使用灵活语法:@Test,返回值类型为空,无参数,必须被public所修饰使用时需要导入Maven仓库中的包import org.junit.Test;*/@Testpublic void getClazz() throws ClassNotFoundException {/*参数为目标类的全路径名:包名+类名获取本类的字节码对象*/Class<?> student1 = Class.forName("cn.tedu.reflection.Student");Class<?> student2 = Student.class;Class<?> student3 = new Student().getClass();System.out.println(student1);//直接打印获取到的字节码兑象System.out.println(student2.getName());//打印类的全路径名System.out.println(student3.getName());//打印类的全路径名System.out.println(student3.getSimpleName());//打印类的类名System.out.println(student3.getPackage());//获取包对象System.out.println(student3.getPackage().getName());//获取包名}}
- 获取构造方法
getConstructor(参数类型列表)————获取公开的构造方法
getConstructors()———获取所有的公开的构造方法
暴力反射getDeclaredConstructors()——-获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)示例代码
//使用单元测试方法获取构造方法@Testpublic void getConstruct(){Class<?> clazz = Student.class;//获取所有公开构造方法,并存入数组Constructor<?>[] cs = clazz.getConstructors();//System.out.println(Arrays.toString(cs));for (Constructor<?> i : cs){System.out.println(i.getName());//获取当前构造函数的名称Class<?>[] p = i.getParameterTypes();//获取当前构造方法的参数类型System.out.println(Arrays.toString(p));}}
getMethods()——获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
暴力反射:
getDeclaredMethods()——-获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
示例代码
//通过单元测试获取普通方法@Testpublic void getFunction() throws ClassNotFoundException {Class<?> clazz = Class.forName("cn.tedu.review.Student");//获取所有公共普通方法Method[] ms = clazz.getMethods();//System.out.println(Arrays.toString(ms));for (Method i : ms){System.out.println(i.getName());//获取当前遍历到的方法名Class<?>[] pt = i.getParameterTypes();//获取方法名的参数类型System.out.println(Arrays.toString(pt));//查看当前遍历到的方法参数类型}
- 获取成员变量
getFields()——-获取所有公开的成员变量,包括继承变量
getDeclaredFields()——-获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)示例代码
/*通过单元测试获取成员变量成员变量的修饰符必须为public才能被获取到默认修饰符无法获取*/@Testpublic void getFields(){Class<Student> clazz = Student.class;Field[] fs = clazz.getFields();for (Field i : fs){System.out.println(i.getName());//获取遍历到的属性名System.out.println(i.getType().getName());//获取遍历到的属性名的类型名}}
反射创建新实例
clazz.newInstance();——执行无参构造创建对象
clazz.newInstance(666,”海绵宝宝”);——执行含参构造创建对象
clazz.getConstructor(int.class,String.class)——获取构造方法反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法
暴力反射
指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。
示例代码
暴力反射所需要的物料类
package cn.tedu.review;/*** 用于测试暴力反射*/public class Person {private String name;private int age;private void find(String s,int n){System.out.println(s + ":太热了,怎么破," + n + n + n + n);}private void update(){System.out.println("不需 要升级");}}
使用暴力反射
package cn.tedu.review;import com.sun.jmx.snmp.SnmpUnknownAccContrModelException;import org.junit.Test;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/*** 测试暴力反射*/public class TestReflect2 {@Testpublic void getFields() throws NoSuchFieldException, InstantiationException, IllegalAccessException {Class<?> clazz = Person.class;//获取私有属性name属性的字节码对象Field filed = clazz.getDeclaredField("name");//使用获取到的私有属性对象获取对应信息System.out.println(filed.getName());System.out.println(filed.getType().getName());/*给指定属性设置值暴力反射需要设置私有资源可见的权限set(m,n)----m指要设置值的对象名,n指要设置的具体值需要先使用字节码对象创建需要的目标对象*/filed.setAccessible(true);Object obj = clazz.newInstance();//使用属性对象设置obj的name值filed.set(obj,"马钊");System.out.println(filed.get(obj));}@Testpublic void getFunction() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {Class<Person> clazz = Person.class;/*使用暴力反射获取私有方法getDeclaredMethod(m,x,y,z····)m指需要获取的方法名x,y,z···指方法参数,传入的为字节码对象。*/Method method = clazz.getDeclaredMethod("find", String.class,int.class);method.setAccessible(true);//需要确定对象来执行获取到的find()Object obj = clazz.newInstance();//使用invoke给对象obj执行方法method.invoke(obj,"马钊",5);}}
