关于反射

getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段。

🥚Java反射 - 图1

顺便记一下:

@Override这个标签

  1. 可以当作注释用,没什么特别的

  2. 可以告诉读你代码的人,这是对它父类方法的重写,其实很多代码规范没有为什么,规范就是规范,代码的可读性还是很重要的。

  3. 编译器可以给你验证@Override下面的方法名称是否是你父类中所有的,如果没有就会报错。

比如当你想要在子类中重写父类的一个方法,但是你把名字打错了,当你写了@Override编译器会提示你,你写的这个方法父类中没有;但是如果你没有写@Override编译器就会觉得这个是你子类中写的新的方法,并不会报错,到时候你debug还是很麻烦的一件事。

摘自【https://blog.csdn.net/upc1607020107/article/details/81274398】感觉这个博主说的就很好了,就直接摘抄过来了

反射的其他两种

  1. String str = "test";
  2. System.out.println(str.getClass());
  3. //静态方法
  4. Class class_name = Class.forName("java.lang.String");

getDeclaredField():获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段。

Class类提供了以下几个方法来获取Method

  • Method getMethod(name, Class...):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

需要执行的话,就需要将方法名传入invoke()方法。有以下两种方式

  1. System.out.println(substring.invoke(test));
  2. //调用带参数的方法,需要传参
  3. System.out.println(substring.invoke(test,"admin"));

执行命令的方法

  1. Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")),"calc");

关于Final 修饰符,它可以用来修饰类,方法,变量

  1. 修饰类:当一个类使用final修饰时,表明这个类不能被继承。

🥚Java反射 - 图2

  1. 修饰方法,表明这个方法被锁定,任何继承这个类之后都不能修改这个方法的含义。
  2. 修饰变量,这个使用的是最多的,也是了解final修饰符的主要原因之一,主要记住一点就是使用final修饰的变量,再初始化之后就不能被修改。

Class.forName(className) 相当于Class.forName(className, true, currentLoader

第⼆个参数表示是否初始化,在forName 的时候,构造函数并不会执⾏,而是执⾏类初始化。他会执行static{}静态块里面的内容

  1. package com.test;
  2. import java.io.IOException;
  3. public class web {
  4. public static void main(String[] args) throws Exception {
  5. Class.forName("com.test.Calc");
  6. }
  7. }
  8. class Calc{
  9. static {
  10. try {
  11. Runtime.getRuntime().exec("calc");
  12. } catch (IOException e) {
  13. e.printStackTrace();
  14. }
  15. }
  16. }

反射原理

反射就是对于任意一个类,可以知道它的所有属性和方法,对于任意一个对象都能调用它的任意一个方法,在运行状态中,动态调用方法的功能
获取对象的三种方式
  1. Class.forName()
  1. Class aClass = Class.forName("com.reflecttest.Person");
  2. System.out.println(aClass);
  1. 类名.class
  1. Class personClass = Person.class;
  2. System.out.println(personClass);
  1. 对象.getClass()
  1. Person person = new Person();
  2. Class aClass1 = person.getClass();
  3. System.out.println(aClass1);

获取对象的功能的13种常用方法

  1. package com.reflecttest;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. public class ReflectDemo1 {
  6. public static void main(String[] args) throws Exception {
  7. /*
  8. * 反射就是对于任意一个类,可以知道它的所有属性和方法,对于任意一个对象都能调用它的任意一个方法
  9. * 在运行状态中,动态调用方法的功能
  10. *获取对象的三种方法
  11. * 1. Class.forName()
  12. * 2. 类名.class
  13. * 3. getClass()
  14. * */
  15. Class aClass = Class.forName("com.reflecttest.Person");
  16. System.out.println(aClass);
  17. System.out.println("===========================");
  18. Class personClass = Person.class;
  19. System.out.println(personClass);
  20. System.out.println("===========================");
  21. Person person = new Person();
  22. Class aClass1 = person.getClass();
  23. System.out.println(aClass1);
  24. /*
  25. * 1. 获取对象的功能
  26. * 1.1 获取成员变量
  27. * */
  28. //获取所有的public变量
  29. Field[] fields = personClass.getFields();
  30. for (Field field : fields) {
  31. System.out.println(field);
  32. }
  33. //获取指定的public变量
  34. Field field = personClass.getField("name");
  35. System.out.println(field);
  36. //获取所有成员变量(包括private & protected)
  37. Field[] declaredFields = personClass.getDeclaredFields();
  38. for (Field declaredField : declaredFields) {
  39. System.out.println(declaredField);
  40. }
  41. //获取指定的私有成员变量
  42. Field age = personClass.getDeclaredField("age");
  43. System.out.println(age);
  44. System.out.println("============================================");
  45. /*1.2 获取构造方法
  46. */
  47. Constructor[] constructors = personClass.getConstructors();
  48. for (Constructor constructor : constructors) {
  49. System.out.println(constructor);
  50. }
  51. //获取指定方法(有参无参)
  52. Constructor constructor = personClass.getConstructor(String.class, int.class, String.class);
  53. System.out.println(constructor);
  54. System.out.println("==========================");
  55. Constructor[] declaredConstructors = personClass.getDeclaredConstructors();
  56. for (Constructor declaredConstructor : declaredConstructors) {
  57. System.out.println(declaredConstructor);
  58. }
  59. //1.3 获取成员方法
  60. // 获取所有公有成员方法
  61. Method[] methods = personClass.getMethods();
  62. for (Method method : methods) {
  63. System.out.println(method);
  64. }
  65. //获取指定成员方法
  66. Method method = personClass.getMethod("love");
  67. System.out.println(method);
  68. //操作
  69. method.invoke(person);
  70. System.out.println("========================================");
  71. //获取所有成员方法
  72. Method[] declaredMethods = personClass.getDeclaredMethods();
  73. for (Method declaredMethod : declaredMethods) {
  74. System.out.println(declaredMethod);
  75. }
  76. Method love = personClass.getDeclaredMethod("love");
  77. love.invoke(person);
  78. }
  79. }

访问并修改调用私有属性的时候,出于安全性检查,会拒绝调用,这时可以使用一行代码来忽略这个私有属性的访问权限安全性检测。

反射练习案例

在不修改代码的情况下,创建任意类和执行任意方法

这里主要是涉及到一个配置文件的使用,这里如果是在maven中,参考https://www.yuque.com/m0re/demosec/sr2n6h#PkCid

  1. package com.reflecttest;
  2. import java.io.InputStream;
  3. import java.lang.reflect.Method;
  4. import java.util.Properties;
  5. public class ReflectDemo2 {
  6. public static void main(String[] args) throws Exception {
  7. //创建Properties对象
  8. Properties properties = new Properties();
  9. //加载配置文件,转换为一个集合(使用到加载器)
  10. // 获取class目录下的配置文件
  11. ClassLoader classLoader = ReflectDemo2.class.getClassLoader();//获取同文件的加载器
  12. InputStream is = classLoader.getResourceAsStream("pro.properties");//转换为流
  13. properties.load(is);//载入
  14. //获取配置文件中定义的数据
  15. String className = properties.getProperty("ClassName");
  16. String methodName = properties.getProperty("MethodName");
  17. //加载该类进内存
  18. Class aClass = Class.forName(className);
  19. //创建对象
  20. Object obj = aClass.newInstance();
  21. //获取方法对象
  22. Method method = aClass.getMethod(methodName);
  23. method.invoke(obj);
  24. }
  25. }