1 反射的概念

编译期是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。
运行期是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为 Java 语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息。

Java 反射机制在服务器程序和中间件程序中得到了广泛运用。在服务器端,往往需要根据客户的请求,动态调用某一个对象的特定方法。此外,在 ORM 中间件的实现中,运用 Java 反射机制可以读取任意一个 JavaBean 的所有属性,或者给这些属性赋值。
image.png
Java 反射机制主要提供了以下功能,这些功能都位于java.lang.reflect包。

  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的成员变量和方法。
  • 在运行时调用任意一个对象的方法。
  • 生成动态代理。

    1.1 反射机制的优缺点

    优点:

  • 能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。

  • 与 Java 动态编译相结合,可以实现无比强大的功能。
  • 对于 Java 这种先编译再运行的语言,能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。


缺点:

  • 反射会消耗一定的系统资源,因此,如果不需要动态地创建一个对象,那么就不需要用反射;
  • 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题。

2 反射的使用

  1. class Person {
  2. private String name;
  3. private Integer age;
  4. private String sex;
  5. public String school;
  6. public Person() {
  7. System.out.println("这是一个无参构造函数");
  8. }
  9. private Person(String str) {
  10. System.out.println("这是一个私有有参构造函数,str=" + str);
  11. }
  12. public Person(String name, Integer age, String sex) {
  13. this.name = name;
  14. this.age = age;
  15. this.sex = sex;
  16. System.out.println("这是一个有参构造函数,name=" + name + " ,age=" + age + " sex=" + sex);
  17. }
  18. public void like() {
  19. System.out.println("i like animal");
  20. }
  21. public void work(String str) {
  22. System.out.println("i am a " + str);
  23. }
  24. private void play(Integer age, String str) {
  25. System.out.println("my age is " + age + " years old; " + "i like to play " + str);
  26. }
  27. public String getName() {
  28. return name;
  29. }
  30. public void setName(String name) {
  31. this.name = name;
  32. }
  33. public Integer getAge() {
  34. return age;
  35. }
  36. public void setAge(Integer age) {
  37. this.age = age;
  38. }
  39. public String getSex() {
  40. return sex;
  41. }
  42. public void setSex(String sex) {
  43. this.sex = sex;
  44. }
  45. public String getSchool() {
  46. return school;
  47. }
  48. public void setSchool(String school) {
  49. this.school = school;
  50. }
  51. }

2.1 反射获取属性

  1. public class ReflectTest {
  2. public static void main(String[] args) {
  3. try {
  4. System.out.println("--------------属性--------------");
  5. Class c = Class.forName("com.example.springdemo.com.reflectTest.Person");
  6. //反射获取公共属性
  7. Field f = c.getField("school");
  8. System.out.println("公共属性:" + f.get(c.newInstance()));
  9. //反射获取私有属性
  10. Field f2 = c.getDeclaredField("name");
  11. f2.setAccessible(true);
  12. System.out.println("私有属性:" + f2.get(c.newInstance()));
  13. } catch (ClassNotFoundException | NoSuchMethodException e) {
  14. e.printStackTrace();
  15. } catch (InvocationTargetException e) {
  16. e.printStackTrace();
  17. } catch (InstantiationException e) {
  18. e.printStackTrace();
  19. } catch (IllegalAccessException e) {
  20. e.printStackTrace();
  21. } catch (NoSuchFieldException e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

2.2 反射获取构造函数

  1. public class ReflectTest {
  2. public static void main(String[] args) {
  3. try {
  4. System.out.println("----------构造函数---------");
  5. Class c = Class.forName("com.example.springdemo.com.reflectTest.Person");
  6. //反射获取无参构造函数
  7. Constructor cons = c.getConstructor(null);
  8. cons.newInstance(null);
  9. //反射获取有参构造函数
  10. Constructor cons2 = c.getConstructor(String.class, Integer.class, String.class);
  11. cons2.newInstance("张三", 18, "男");
  12. //反射获取私有有参构造函数
  13. Constructor cons3 = c.getDeclaredConstructor(String.class);
  14. cons3.setAccessible(true);
  15. cons3.newInstance("私有有参构造函数");
  16. //反射获取所有有参构造函数
  17. Constructor[] cons4 = c.getDeclaredConstructors();
  18. Arrays.stream(cons4).forEach(i -> System.out.println("构造函数:" + i));
  19. } catch (ClassNotFoundException | NoSuchMethodException e) {
  20. e.printStackTrace();
  21. } catch (InvocationTargetException e) {
  22. e.printStackTrace();
  23. } catch (InstantiationException e) {
  24. e.printStackTrace();
  25. } catch (IllegalAccessException e) {
  26. e.printStackTrace();
  27. } catch (NoSuchFieldException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. }

2.3 反射获取方法

  1. public class ReflectTest {
  2. public static void main(String[] args) {
  3. try {
  4. System.out.println("----------------方法------------------");
  5. Class c = Class.forName("com.example.springdemo.com.reflectTest.Person");
  6. Method m = c.getMethod("like", null);
  7. m.invoke(c.newInstance(), null);
  8. //反射获取有参方法
  9. Method m2 = c.getMethod("work", String.class);
  10. m2.invoke(c.newInstance(), "coder");
  11. //反射获取私有方法
  12. Method m3 = c.getDeclaredMethod("play", Integer.class, String.class);
  13. m3.setAccessible(true);
  14. m3.invoke(c.newInstance(), 18, "basketball");
  15. } catch (ClassNotFoundException | NoSuchMethodException e) {
  16. e.printStackTrace();
  17. } catch (InvocationTargetException e) {
  18. e.printStackTrace();
  19. } catch (InstantiationException e) {
  20. e.printStackTrace();
  21. } catch (IllegalAccessException e) {
  22. e.printStackTrace();
  23. } catch (NoSuchFieldException e) {
  24. e.printStackTrace();
  25. }
  26. }
  27. }

2.4 通过反射越过泛型检查

  1. public static void invokeList() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
  2. List<Integer> integerList = new ArrayList<>();
  3. integerList.add(123);
  4. integerList.getClass().getMethod("add", Object.class).invoke(integerList,"abc");
  5. for (int i=0;i<integerList.size();i++){
  6. System.out.println(integerList.get(i));
  7. }
  8. // integerList.stream().forEach(System.out::println);
  9. }

输出:

  1. true