内容概况

  • 反射及作用
  • 反射四个核心类
  • 反射在项目中的应用

    什么是反射Reflect

  • 反射是在运行时动态访问类与对象的技术

  • 反射是JDK1.2之后的高级特性,隶属于java.lang.reflect
  • 大多数Java框架都基于反射实现参数配置、动态注入等特性 ```java public class ReflectSample { /**

    • 传统的创建对象方式 */ public static void case1(){ Scanner scanner = new Scanner(System.in); System.out.print(“请输入计算类名:”); String op = scanner.next(); System.out.print(“请输入a:”); int a = scanner.nextInt(); System.out.print(“请输入b:”); int b = scanner.nextInt(); MathOperation mathOperation = null; if(op.equals(“Addition”)){

      1. mathOperation = new Addition();

      }else if(op.equals(“Subtraction”)) {

      1. mathOperation = new Subtraction();

      }else if(op.equals(“Multiplication”)){

      1. mathOperation = new Multiplication();

      }else{

      1. System.out.println("无效的计算类");
      2. return;

      } float result = mathOperation.operate(a, b); System.out.println(result); }

      /**

    • 利用反射创建对象更加灵活 */ public static void case2(){ Scanner scanner = new Scanner(System.in); System.out.print(“请输入计算类名:”); String op = scanner.next(); System.out.print(“请输入a:”); int a = scanner.nextInt(); System.out.print(“请输入b:”); int b = scanner.nextInt(); MathOperation mathOperation = null; try {
      1. mathOperation = (MathOperation) Class.forName("com.imooc.reflect." + op).newInstance();
      }catch(Exception e){
      1. System.out.println("无效的计算类");
      2. return;
      } float result = mathOperation.operate(a, b); System.out.println(result); }
  1. public static void main(String[] args) {
  2. ReflectSample.case2();
  3. }

}

  1. <a name="ZSVr7"></a>
  2. ## 反射的核心类
  3. - Class类
  4. - Constructor构造方法类
  5. - Method方法类
  6. - Field成员变量类
  7. <a name="hzyLt"></a>
  8. ## Class类(描述其他类的一个类)
  9. - Class是JVM中代表“类和接口”的类,和其他的标准的类没有任何区别,只是对其他的类和接口这一个特殊的类的抽象
  10. - Class对象具体包含了某个特定类的结构信息
  11. - 通过Class对象可获取对应类的构造方法、方法、成员变量
  12. - Class核心方法
  13. | 方法 | 用途 |
  14. | --- | --- |
  15. | Class.forName() | 静态方法,用于获取指定Class对象 |
  16. | classObj.newInstance() | 通过默认构造方法创建新的对象 |
  17. | classObj.getConstructor() | 获取指定public修饰构造方法Constructor对象 |
  18. | classObj.getMethod() | 获取指定的public修饰方法Method对象 |
  19. | classObj.getField() | 获取指定的public修饰成员变量Field对象 |
  20. ```java
  21. public class ClassSimple {
  22. public static void main(String[] args) {
  23. try {
  24. Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
  25. Employee employee = (Employee) employeeClass.newInstance();//通过默认的构造方法创建新的对象
  26. System.out.println("employee = " + employee);
  27. } catch (ClassNotFoundException e) {
  28. //类名与类路径书写错误是抛出“类无法找到”异常
  29. e.printStackTrace();
  30. } catch (IllegalAccessException e) {
  31. // 非法访问异常,当在作用域外访问对象方法或成员变量时抛出
  32. e.printStackTrace();
  33. } catch (InstantiationException e) {
  34. // 实例化异常,当对象无法被实例化时抛出的异常,抽象类、接口等无法被实例化
  35. e.printStackTrace();
  36. }
  37. }
  38. }

Constructor构造方法类

  • Constructor类是对Java中的构造方法的抽象。
  • Constructor对象包含了具体的某个具体构造方法的声明。
  • 通过Constructor对象调用带参构造方法创建对象
  • Constructor类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getConstructor() | 获取指定public修饰的构造方法对象 | | constructorObj.newInstance() | 通过对应的构造方法创建对象 |
  1. /**
  2. * 利用带参构造方法创建对象
  3. */
  4. public class ConstructorSimple {
  5. public static void main(String[] args) {
  6. try {
  7. Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
  8. Constructor<?> employeeClassConstructor = employeeClass.getConstructor(new Class[]{
  9. Integer.class, String.class, Float.class, String.class
  10. });
  11. Employee employee = (Employee) employeeClassConstructor.newInstance(1, "wkq", 12f, "某某部门");
  12. System.out.println("employee = " + employee);
  13. } catch (ClassNotFoundException e) {
  14. e.printStackTrace();
  15. } catch (NoSuchMethodException e) {
  16. //没有找到与之对应格式的方法
  17. e.printStackTrace();
  18. } catch (IllegalAccessException e) {
  19. e.printStackTrace();
  20. } catch (InstantiationException e) {
  21. //实例化异常
  22. e.printStackTrace();
  23. } catch (InvocationTargetException e) {
  24. // 目标调用异常,当被调用的方法内部跑出来异常而没有被捕获时
  25. e.printStackTrace();
  26. }
  27. }

Method方法类

  • Method对象指代某个类中的方法的描述
  • Method对象使用classObj.getMethods()方法获取
  • 通过Method对象调用指定对象的对应方法、
  • Method类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getMethod() | 获取指定public修饰的方法对象 | | methodObj.invoke() | 调用指定对象的对应方法 |
  1. public class MethodSimple {
  2. public static void main(String[] args) {
  3. try {
  4. Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
  5. Constructor<?> constructor = employeeClass.getConstructor(new Class[]{
  6. Integer.class, String.class, Float.class, String.class
  7. });
  8. Employee employee = (Employee) constructor.newInstance(12, "李磊", 12f, "研发部门");
  9. Method updateSalaryMethod = employeeClass.getMethod("updateSalary", new Class[]{
  10. Float.class
  11. });
  12. Employee newEmployee = (Employee) updateSalaryMethod.invoke(employee, new Object[]{1000f});
  13. System.out.println("newEmployee = " + newEmployee);
  14. } catch (ClassNotFoundException e) {
  15. e.printStackTrace();
  16. } catch (NoSuchMethodException e) {
  17. e.printStackTrace();
  18. } catch (IllegalAccessException e) {
  19. e.printStackTrace();
  20. } catch (InstantiationException e) {
  21. e.printStackTrace();
  22. } catch (InvocationTargetException e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

Field成员变量类

  • Field对应某个具体类中的成员变量的声明
  • Field对象使用classObj.getField()方法获取
  • 通过Field对象可为某对象成员变量赋值、取值
  • 无论是下面的getField()还是后面的getMethod()方法,这些get方法开头的,默认都是获取public修饰的成员变量或者方法,如果尝试获取私有的成员方法或者成员变量,就会抛出NoSuchXXXException
  • Field类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getField() | 获取指定public修饰的成员变量 | | fieldObj.set() | 为某对象指定成员变量赋值 | | fieldObj.get() | 获取某对象指定成员变量数值 |
  1. public class FiledSimple {
  2. public static void main(String[] args) {
  3. try {
  4. Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
  5. Constructor<?> employeeClassConstructor = employeeClass.getConstructor(new Class[]{
  6. Integer.class, String.class, Float.class, String.class
  7. });
  8. Employee employee = (Employee) employeeClassConstructor.newInstance(new Object[]{
  9. 112, "李磊", 12f, "研发部"
  10. });
  11. Field employeeClassEnameField = employeeClass.getField("ename");
  12. Object o = employeeClassEnameField.get(employee);
  13. System.out.println("o = " + o);
  14. employeeClassEnameField.set(employee,"王开琦");
  15. System.out.println("employee = " + employee);
  16. } catch (ClassNotFoundException e) {
  17. e.printStackTrace();
  18. } catch (NoSuchMethodException e) {
  19. e.printStackTrace();
  20. } catch (IllegalAccessException e) {
  21. e.printStackTrace();
  22. } catch (InstantiationException e) {
  23. e.printStackTrace();
  24. } catch (InvocationTargetException e) {
  25. e.printStackTrace();
  26. } catch (NoSuchFieldException e) { // 没有找到对应成员变量时抛出的异常
  27. e.printStackTrace();
  28. }
  29. }

getDeclared系列方法

  • getDeclaredConstructor(s)|Method(s)|Field(s)获取对应对象。带s的返回当前类中所有的。
  • getConstructor(s)|Method(s)|Field(s)只能获取public对象,get是getDeclared的一个子集。
  • 访问非作用域内构造方法、方法、成员变量,会抛出异常。
  • 以下代码可以根据一个类对象解析这个对象, ```java public class GetDeclaredSimpleSimple { public static void main(String[] args) {
    1. try {
    2. Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
    3. Constructor<?> employeeClassConstructor = employeeClass.getConstructor(new Class[]{
    4. Integer.class, String.class, Float.class, String.class
    5. });
    6. Employee employee = (Employee) employeeClassConstructor.newInstance(new Object[]{
    7. 12, "李磊", 12f, "研发部"
    8. });
    9. /* Field[] fields = employeeClass.getFields();
    10. for (Field field : fields) {
    11. System.out.println("field.getName() = " + field.getName());
    12. }*/
    13. /* Method[] declaredMethods = employeeClass.getDeclaredMethods();
    14. for (Method declaredMethod : declaredMethods) {
    15. System.out.println("declaredMethod.getName() = " + declaredMethod.getName());
    16. }*/
    17. Field[] declaredFields = employeeClass.getDeclaredFields();
    18. for (Field declaredField : declaredFields) {
    19. System.out.println("declaredField.getName() = " + declaredField.getName());
    20. if (declaredField.getModifiers() == 1) {
    21. Object val = declaredField.get(employee);
    22. System.out.println("public \"+declaredField.getName()+\"= " + val);
    // declaredField.getModifiers() 获取访问修饰符,如果值为1,说明当前属性或方法是public修饰的
    1. } else if (declaredField.getModifiers() == 2) { //private修饰
    2. // subString()代表字符串截取的意思 substring(0, 1)表示第一个字母 substring(1)表示第一个字母之后的字母
    3. String methodName = "get" + declaredField.getName().substring(0, 1).toUpperCase() + declaredField.getName().substring(1);
    4. Method method = employeeClass.getMethod(methodName);
    5. Object val = method.invoke(employee);
    6. System.out.println("private "+declaredField.getName()+" = " + val);
    7. }
    8. }
    9. } catch (ClassNotFoundException e) {
    10. e.printStackTrace();
    11. } catch (NoSuchMethodException e) {
    12. e.printStackTrace();
    13. } catch (IllegalAccessException e) {
    14. e.printStackTrace();
    15. } catch (InstantiationException e) {
    16. e.printStackTrace();
    17. } catch (InvocationTargetException e) {
    18. e.printStackTrace();
    19. }
    } }
  1. <a name="ztq3O"></a>
  2. ## 反射在项目中的应用
  3. 反射提供了 `运行时` 对类的成员变量和方法提供了访问和调用的机制
  4. ```java
  5. language=com.imooc.i18n.En // 配置文件内容
  6. public class Application {
  7. public static void say() {
  8. Properties properties = new Properties();
  9. String configPath = Application.class.getResource("/config.properties").getPath();
  10. try {
  11. configPath = new URLDecoder().decode(configPath, "UTF-8");
  12. properties.load(new FileInputStream(configPath));
  13. String language = properties.getProperty("language");
  14. I18N i18n = (I18N) Class.forName(language).newInstance();
  15. i18n.say();
  16. System.out.println("i18n.say() = " + i18n.say());
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. }
  20. }
  21. public static void main(String[] args) {
  22. Application.say();
  23. }
  24. }

总结

什么是反射

  • 反射(Reflect)是在运行时 动态访问类与对象的技术。
  • 反射是JDK1.2版本后的高级特性,隶属于java.lang.reflect。
  • 大多数Java框架都基于反射实现参数配置,动态注入、动态的创建类,创建对象等特性。

    反射的核心类

  • Class

  • Constructor构造方法类
  • Method方法类
  • Field 成员变量类

    Class类

  • Class是JVM中代表“类和接口” 的类

  • Class对象具体包含了某个特定类的结构信息
  • 通过Class对象可获取对应类的构造方法、方法、成员变量
  • Class类核心方法 | 方法 | 用途 | | —- | —- | | Class.forName() | 静态方法,用于获取指定Class对象 | | classObj.newInstance() | 通过默认构造方法创建新的对象 | | classObj.getConstructor() | 获取指定public修饰构造方法Constructor对象 | | classObj.getMethod() | 获取指定的public修饰方法Method对象 | | classObj.getField() | 获取指定的public修饰成员变量Field对象 |

构造方法类

  • Constructor类是对java类中构造方法的抽象
  • Constructor对象包含了具体类的某个构造方法的声明
  • 通过Constructor对象调用带参构造方法创建对象 | 方法 | 用途 | | —- | —- | | classObj.getMethod() | 获取指定public修饰的方法对象 | | methodObj.invoke() | 调用指定对象的对应方法 |

Method方法类

  • Method对象指代某个类中的方法的描述
  • Method对象使用classObj.getMethod() 方法获取
  • 通过对象调用指定对象的对应方法 | 方法 | 用途 | | —- | —- | | classObj.getMethod() | 获取指定public修饰的方法对象 | | methodObj.invoke() | 调用指定对象的对应方法 |

Field成员变量类

  • Field对应某个具体类中的成员变量的声明
  • Field对象使用classObj.getField()方法获取
  • 通过Field对象可为某对象成员变量赋值、取值
  • 无论是下面的getField()还是后面的getMethod()方法,这些get方法开头的,默认都是获取public修饰的成员变量或者方法,如果尝试获取私有的成员方法或者成员变量,就会抛出NoSuchXXXException
  • Field类核心方法 | 方法 | 用途 | | —- | —- | | classObj.getField() | 获取指定public修饰的成员变量 | | fieldObj.set() | 为某对象指定成员变量赋值 | | fieldObj.get() | 获取某对象指定成员变量数值 |