反射

框架 ->半成品软件 ->灵魂 -> 反射

前言

java安全从反序列化漏洞说起,反序列化漏洞从反射开始说起
反射是大多数语言都必不可少部分
对象可以通过反射获取他的类,类可以通过反射拿到所有方法(包括私有),拿到的方法可以调用

总之通过反射,我们可以将Java这个静态语言附加上动态特性

简介

反射机制:

将类的各个组成部分分装为其他对象
image-20211214180220206.png

好处

  • 在程序的运行过程中,去操作这些对象
  • 可以解耦,提高程序的可扩展性

获取class对象的三种方式

  1. Source源代码阶段:

第一阶段,java代码只有字节码文件,并没有进入到内存

需要手动的加载进内存,生成class对象

多用于配置文件,将类名定义在配置文件中,读取文件,加载类

  1. class.forName("全类名") //将字节码文件加载进内存,返回class对象
  1. package live.yanmu.domain;
  2. public class res1 {
  3. public static void main(String[] args) throws Exception {
  4. Class aClass = Class.forName("live.yanmu.domain.dd.person");
  5. System.out.println(aClass);
  6. }
  7. }
  1. Class类对象阶段

已经加载进内存了,只是并没有获取到它

多用于参数的传递

  1. 类名.class
  1. package live.yanmu.domain;
  2. import live.yanmu.domain.dd.person;
  3. public class res1 {
  4. public static void main(String[] args) throws Exception {
  5. Class<person> personClass = person.class;
  6. System.out.println(personClass);
  7. }
  8. }
  1. Runtime运行时阶段

已经有person对象了

用object对象的方法来获取

多用于对象的字节码方式

  1. 对象.getclass()
  1. package live.yanmu.domain;
  2. import live.yanmu.domain.dd.person;
  3. public class res1 {
  4. public static void main(String[] args) throws Exception {
  5. person person = new person();
  6. Class aClass = person.getClass();
  7. System.out.println(aClass);
  8. }
  9. }

比较

同一个字节码文件,在一次程序的运行过程中,只会被加载一次,不论是通过什么方式的class对象都是同一个

使用

获取的功能

  1. 获取成员变量们
    • Field[] getFields()
    • Field getField(String name)
    • Field[] getDeclaredFields()
    • Field getDeclaredField(String name)
  2. 获取构造方法们
    • Constructor<?>[] getConstructors()
    • Constructor getConstructor(类…parameterTypes)
    • Constructor getDeclaredConstructor(类…parameterTypes)
    • Constructor<?>[] getDeclaredConstructors()
  3. 获取成员方法们
    | 方法[] | getMethods() | | —- | —- | | 方法[] | getDeclaredMethods() | | 方法 | getMethod(String name, 类<?>... parameterTypes) | | 方法 | getDeclaredMethod(String name, 类<?>... parameterTypes) |

  4. 获取类名

    • String getName()

Field:成员变量

  • 操作
    1. 设置值
      set(Object obj,Object value)
    2. 获取值
      get(Object obj)

代码演示

  1. package live.yanmu.domain;
  2. import live.yanmu.domain.dd.person;
  3. import java.lang.reflect.Field;
  4. public class res1 {
  5. public static void main(String[] args) throws Exception {
  6. Class personClass = person.class;
  7. //获取所有public修饰的成员变量的
  8. Field[] fields = personClass.getFields();
  9. for (Field field : fields) {
  10. //遍历快捷键iter
  11. System.out.println(field);
  12. }
  13. System.out.println("---------------------");
  14. //获取指定public的成员变量
  15. Field a = personClass.getField("a");
  16. //获取成员变量a的值
  17. person person = new person();
  18. Object o = a.get(person);
  19. System.out.println(o);
  20. a.set(person,3);
  21. System.out.println("-------------------------");
  22. System.out.println(person);
  23. System.out.println("=======================================");
  24. //获取所有的成员变量,不考虑什么修饰符
  25. Field[] declaredFields = personClass.getDeclaredFields();
  26. for (Field declaredField : declaredFields) {
  27. System.out.println(declaredField);
  28. }
  29. //在使用不是public修饰符修饰的时候
  30. Field d = personClass.getDeclaredField("d");
  31. //忽略安全权限修饰符检测
  32. //home转到光标最前面,end转到最后面
  33. //暴力反射
  34. d.setAccessible(true);
  35. Object o1 = d.get(person);
  36. System.out.println(o1);
  37. }
  38. }
  1. package live.yanmu.domain;
  2. import live.yanmu.domain.dd.person;
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.Field;
  5. public class res1 {
  6. public static void main(String[] args) throws Exception {
  7. Class personClass = person.class;
  8. //获取构造方法->创建对象
  9. Constructor constructor = personClass.getConstructor(String.class, int.class);
  10. System.out.println(constructor);
  11. Object yanmu = constructor.newInstance("yanmu", 11);
  12. System.out.println(yanmu);
  13. //也可以用空参的构造创建对象
  14. //constructor.setAccessible(true);
  15. }
  16. }
  1. package live.yanmu.domain;
  2. import live.yanmu.domain.dd.person;
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Method;
  6. public class res1 {
  7. public static void main(String[] args) throws Exception {
  8. Class personClass = person.class;
  9. //获取指定名称的方法
  10. Method eat = personClass.getMethod("eat");
  11. person person = new person();
  12. //执行空参方法
  13. eat.invoke(person);
  14. Method eat1 = personClass.getMethod("eat", String.class);
  15. //执行有参方法
  16. eat1.invoke(person,"饭");
  17. System.out.println("=========================");
  18. //获取所有public修饰的方法
  19. Method[] methods = personClass.getMethods();
  20. for (Method method : methods) {
  21. //含有object里面的方法
  22. System.out.println(method);
  23. System.out.println(method.getName());
  24. // method.setAccessible(true);
  25. }
  26. }
  27. }
  1. package live.yanmu.domain.dd;
  2. public class person {
  3. private String name;
  4. private int age;
  5. public int a;
  6. protected int b;
  7. int c;
  8. private int d;
  9. public person(){
  10. }
  11. public person(String name, int age) {
  12. this.name = name;
  13. this.age = age;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public String getName() {
  22. return name;
  23. }
  24. public int getAge() {
  25. return age;
  26. }
  27. @Override
  28. public String toString() {
  29. return "person{" +
  30. "name='" + name + '\'' +
  31. ", age=" + age +
  32. ", a=" + a +
  33. ", b=" + b +
  34. ", c=" + c +
  35. ", d=" + d +
  36. '}';
  37. }
  38. public void eat(){
  39. System.out.println("eat........");
  40. }
  41. public void eat(String aaa){
  42. System.out.println("你喜欢吃"+aaa);
  43. }
  44. }

相关面试题

JAVA 反射做了什么事情

反射是根据字节码获取类的信息或调用方法
从开发者角度来讲,反射最大意义是提高程序的灵活性
Java本身是一个静态语言,但反射特性允许运行时动态修改类的定义和属性等,达到动态效果

JAVA反射可以修改Final字段吗

可以做到
主要是用到setAccessible功能

  1. //也叫做暴力反射
  2. xx.setAccessible(true)

传统反射方法加入黑名单怎么绕过

可以使用多种类和方法

  1. ReflectUtil.forName
  2. BytecodeDescriptor
  3. ClassLoader.loadClass
  4. sun.reflect.misc.MethodUtil
  5. sun.reflect.misc.FieldUtil
  6. sun.reflect.misc.ConstructorUtil
  7. MethodAccessor.invoke
  8. JSClassLoader.invoke
  9. JSClassLoader.newInstance