反射

概念

Reflection(反射) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,也有称作“自省”。

反射需要使用的API

获取字节码对象

Class.forName(“类的全路径”);

类名.class

对象.getClass();

常用方法
  1. 获取包名 类名
    clazz.getPackage().getName()——包名
    clazz.getSimpleName()——类名
    clazz.getName()——完整类名
    示例代码
  1. package cn.tedu.reflection;
  2. import org.junit.Test;
  3. /**
  4. * 测试反射技术
  5. */
  6. public class TestReflect {
  7. /*
  8. 单元测试:是java运行测试的最小单位,使用灵活
  9. 语法:@Test,返回值类型为空,无参数,必须被public所修饰
  10. 使用时需要导入Maven仓库中的包
  11. import org.junit.Test;
  12. */
  13. @Test
  14. public void getClazz() throws ClassNotFoundException {
  15. /*
  16. 参数为目标类的全路径名:包名+类名
  17. 获取本类的字节码对象
  18. */
  19. Class<?> student1 = Class.forName("cn.tedu.reflection.Student");
  20. Class<?> student2 = Student.class;
  21. Class<?> student3 = new Student().getClass();
  22. System.out.println(student1);//直接打印获取到的字节码兑象
  23. System.out.println(student2.getName());//打印类的全路径名
  24. System.out.println(student3.getName());//打印类的全路径名
  25. System.out.println(student3.getSimpleName());//打印类的类名
  26. System.out.println(student3.getPackage());//获取包对象
  27. System.out.println(student3.getPackage().getName());//获取包名
  28. }
  29. }
  1. 获取构造方法
    getConstructor(参数类型列表)————获取公开的构造方法
    getConstructors()———获取所有的公开的构造方法
    暴力反射
    getDeclaredConstructors()——-获取所有的构造方法,包括私有
    getDeclaredConstructor(int.class,String.class)
    示例代码
  1. //使用单元测试方法获取构造方法
  2. @Test
  3. public void getConstruct(){
  4. Class<?> clazz = Student.class;
  5. //获取所有公开构造方法,并存入数组
  6. Constructor<?>[] cs = clazz.getConstructors();
  7. //System.out.println(Arrays.toString(cs));
  8. for (Constructor<?> i : cs){
  9. System.out.println(i.getName());//获取当前构造函数的名称
  10. Class<?>[] p = i.getParameterTypes();//获取当前构造方法的参数类型
  11. System.out.println(Arrays.toString(p));
  12. }
  13. }
  1. getMethods()——获取所有可见的方法,包括继承的方法
    getMethod(方法名,参数类型列表)

暴力反射:

getDeclaredMethods()——-获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)

示例代码
  1. //通过单元测试获取普通方法
  2. @Test
  3. public void getFunction() throws ClassNotFoundException {
  4. Class<?> clazz = Class.forName("cn.tedu.review.Student");
  5. //获取所有公共普通方法
  6. Method[] ms = clazz.getMethods();
  7. //System.out.println(Arrays.toString(ms));
  8. for (Method i : ms){
  9. System.out.println(i.getName());//获取当前遍历到的方法名
  10. Class<?>[] pt = i.getParameterTypes();//获取方法名的参数类型
  11. System.out.println(Arrays.toString(pt));//查看当前遍历到的方法参数类型
  12. }
  1. 获取成员变量
    getFields()——-获取所有公开的成员变量,包括继承变量
    getDeclaredFields()——-获取本类定义的成员变量,包括私有,但不包括继承的变量
    getField(变量名)
    getDeclaredField(变量名)
    示例代码
  1. /*
  2. 通过单元测试获取成员变量
  3. 成员变量的修饰符必须为public才能被获取到
  4. 默认修饰符无法获取
  5. */
  6. @Test
  7. public void getFields(){
  8. Class<Student> clazz = Student.class;
  9. Field[] fs = clazz.getFields();
  10. for (Field i : fs){
  11. System.out.println(i.getName());//获取遍历到的属性名
  12. System.out.println(i.getType().getName());//获取遍历到的属性名的类型名
  13. }
  14. }
  1. 反射创建新实例
    clazz.newInstance();——执行无参构造创建对象
    clazz.newInstance(666,”海绵宝宝”);——执行含参构造创建对象
    clazz.getConstructor(int.class,String.class)——获取构造方法

  2. 反射调用成员变量
    clazz.getDeclaredField(变量名);//获取变量
    clazz.setAccessible(true);//使私有成员允许访问
    f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
    f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null

  3. 反射调用成员方法
    Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
    m.setAccessible(true);//使私有方法允许被调用
    m.invoke(实例,参数数据);//让指定实例来执行该方法

暴力反射

指可以将程序中的私有的属性或者方法通过反射技术,暴力的获取到资源。

示例代码

暴力反射所需要的物料类

  1. package cn.tedu.review;
  2. /**
  3. * 用于测试暴力反射
  4. */
  5. public class Person {
  6. private String name;
  7. private int age;
  8. private void find(String s,int n){
  9. System.out.println(s + ":太热了,怎么破," + n + n + n + n);
  10. }
  11. private void update(){
  12. System.out.println("不需 要升级");
  13. }
  14. }

使用暴力反射

  1. package cn.tedu.review;
  2. import com.sun.jmx.snmp.SnmpUnknownAccContrModelException;
  3. import org.junit.Test;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.InvocationTargetException;
  6. import java.lang.reflect.Method;
  7. /**
  8. * 测试暴力反射
  9. */
  10. public class TestReflect2 {
  11. @Test
  12. public void getFields() throws NoSuchFieldException, InstantiationException, IllegalAccessException {
  13. Class<?> clazz = Person.class;
  14. //获取私有属性name属性的字节码对象
  15. Field filed = clazz.getDeclaredField("name");
  16. //使用获取到的私有属性对象获取对应信息
  17. System.out.println(filed.getName());
  18. System.out.println(filed.getType().getName());
  19. /*
  20. 给指定属性设置值
  21. 暴力反射需要设置私有资源可见的权限
  22. set(m,n)----m指要设置值的对象名,n指要设置的具体值
  23. 需要先使用字节码对象创建需要的目标对象
  24. */
  25. filed.setAccessible(true);
  26. Object obj = clazz.newInstance();
  27. //使用属性对象设置obj的name值
  28. filed.set(obj,"马钊");
  29. System.out.println(filed.get(obj));
  30. }
  31. @Test
  32. public void getFunction() throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
  33. Class<Person> clazz = Person.class;
  34. /*
  35. 使用暴力反射获取私有方法
  36. getDeclaredMethod(m,x,y,z····)
  37. m指需要获取的方法名
  38. x,y,z···指方法参数,传入的为字节码对象。
  39. */
  40. Method method = clazz.getDeclaredMethod("find", String.class,int.class);
  41. method.setAccessible(true);
  42. //需要确定对象来执行获取到的find()
  43. Object obj = clazz.newInstance();
  44. //使用invoke给对象obj执行方法
  45. method.invoke(obj,"马钊",5);
  46. }
  47. }