反射的详细了解

有关反射的异常:

  1. InstantiationException 实例化异常:通常由没有构造方法,或没有public构造方法产生的异常,有此异常也会有IllegalAccessException 该异常。
  2. IllegalAccessException 非法访问异常:通常由访问修饰符不是public产生
  3. ClassNotFoundException 找不到类异常:通常由路径写错或类名写错产生

一:反射的作用

  1. 动态的创建一个对象,不需要new创建一个对象(更灵活,忽略访问权限)
  2. 操作的是运行编译后的对象

在java.lang包下有Reflec类
QQ截图20210109150746.png
反射的api
QQ截图20210109152856.png
invoke调用

二:反射的运行流程

  • 第一步:由Java编译器进行源代码编译,得到相应类的字节码.class文件。
  • 第二步:生成class文件之后,通过ClassLoader类加载器加载进内存,Java字节码由JVM执行解释给目标计算机。
  • 第三步,目标计算机将结果呈现给我们计算机用户;因此,Java并不是编译机制,而是解释机制.class文件才可以在不同平台上运行加载。

三:利用反射机制获取类的三种方式

第一种:new一个对象,使用如下方式获取

  1. Person person01=new Person();
  2. Class clazz=person01.getClass();

第二种:直接获取

  1. Class clazz=类名.class;

第三种:使用Class.forName(“”)方法

  1. Class clazz=Class.forName("包名.类名");

第四种:使用类加载器的方式获取

  1. ClassLoader classLoader = RelfectTest.class.getClassLoader();
  2. Class<?> clazz = classLoader.loadClass("com.java.Person");

总结:三种方式获取的都是同一个对象

四:利用反射机制获取一个类的构造方法和属性

Class的 newInstance()方法创建对象 创建对象的前提条件:必须要有构造方法,权限必须为public

  1. package com.java;
  2. import org.junit.Test;
  3. import java.lang.reflect.Constructor;
  4. import java.lang.reflect.Field;
  5. import java.lang.reflect.Method;
  6. public class RelfectTest {
  7. @Test
  8. public void Test() {
  9. Person person = new Person("hanmeimei", 20);
  10. person.showAge(161);
  11. System.out.println(person.toString());
  12. }
  13. @Test
  14. public void Test01() throws Exception {
  15. Class clazz = Person.class;
  16. /*通过反射创建对象*/
  17. Constructor cons = clazz.getConstructor(String.class, Integer.class);
  18. //创建运行时实例
  19. Person person = (Person) cons.newInstance("tom", 12);
  20. System.out.println(person.toString());
  21. /*通过反射调用对象指定的属性,方法*/
  22. //调用age属性,调用公共的属性
  23. Field age = clazz.getDeclaredField("age");
  24. //允许调用私有属性和方法
  25. age.setAccessible(true);
  26. age.set(person, 23);
  27. //调用name属性
  28. System.out.println(person.toString());
  29. /*调用公共方法*/
  30. Method showAge = clazz.getDeclaredMethod("showAge", Integer.class);
  31. /*调用方法,invoke调用的意思*/
  32. showAge.invoke(person, 20);
  33. /*调用私有的构造器*/
  34. Constructor cons1 = clazz.getDeclaredConstructor(String.class);
  35. //允许调用私有的属性和方法
  36. cons1.setAccessible(true);
  37. Object person1 = cons1.newInstance("lili");
  38. System.out.println(person1.toString());
  39. //调用私有方法
  40. Method showName = clazz.getDeclaredMethod("showName");
  41. showName.setAccessible(true);
  42. showName.invoke(person1);
  43. }
  44. }

1. 反射动态创建一个对象的应用

  1. public Object getNewInstance(String path) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
  2. Class<?> aClass = Class.forName(path);
  3. Object newInstance = aClass.newInstance();
  4. return newInstance;
  5. }
  6. @Test
  7. public void Test04() {
  8. for (int i = 1; i < 100; i++) {
  9. Random random = new Random();
  10. int num = random.nextInt(3);
  11. String path = " ";
  12. switch (num) {
  13. case 0:
  14. path = "java.util.Date";
  15. break;
  16. case 1:
  17. path = "com.java.Person";
  18. break;
  19. case 2:
  20. path = "java.lang.Object";
  21. default:
  22. break;
  23. }
  24. Object newInstance = null;
  25. try {
  26. newInstance = getNewInstance(path);
  27. System.out.println(newInstance);
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. }

2.通过反射获取一个类的所有信息(包含private,但不包含父类和实现类)和他的父类实现类的public信息

  1. @Test
  2. public void Test05() {
  3. Class<Person> clazz = Person.class;
  4. //获取所有公共的属性
  5. Field[] fields = clazz.getFields();
  6. for (Field field : fields) {
  7. System.out.println(field);
  8. }
  9. }
  10. @Test
  11. public void Test06() {
  12. Class<Person> clazz = Person.class;
  13. //获取当前实例中所有属性(私有公有全部获取),不包含父类的
  14. Field[] fields = clazz.getDeclaredFields();
  15. for (Field field : fields) {
  16. System.out.println(field);
  17. }
  18. }
  19. @Test
  20. public void Test07() {
  21. Class<Person> clazz = Person.class;
  22. //获取当前实例中所有属性(私有公有全部获取),不包含父类的
  23. Field[] fields = clazz.getDeclaredFields();
  24. for (Field field : fields) {
  25. //获取权限修饰符
  26. int modifiers = field.getModifiers();
  27. System.out.println(Modifier.toString(modifiers));
  28. //获取数据类型
  29. Class<?> type = field.getType();
  30. System.out.println(type);
  31. //获取变量名
  32. String name = field.getName();
  33. System.out.println(name);
  34. }
  35. }
  36. @Test
  37. public void Test08() {
  38. Class<Person> clazz = Person.class;
  39. //获取当前类的所有公共的方法(包含父类的,实现类的)
  40. Method[] methods = clazz.getMethods();
  41. for (Method method : methods) {
  42. Parameter[] parameters = method.getParameters();
  43. for (Parameter parameter : parameters) {
  44. System.out.println(parameter.getName());
  45. }
  46. }
  47. //获取当前类的所有方法(不包含继承的,实现的,忽略访问权限)
  48. Method[] declaredMethods = clazz.getDeclaredMethods();
  49. for (Method declaredMethod : declaredMethods) {
  50. System.out.println(declaredMethod);
  51. }
  52. }
  53. @Test
  54. public void Test09() {
  55. Class<Person> clazz = Person.class;
  56. //获取当前类的所有方法(不包含继承的,实现的,忽略访问权限)
  57. Method[] declaredMethods = clazz.getDeclaredMethods();
  58. for (Method declaredMethod : declaredMethods) {
  59. //获取访问修饰符
  60. int modifiers = declaredMethod.getModifiers();
  61. System.out.print(Modifier.toString(modifiers) + "\t");
  62. //获取返回值类型
  63. Class<?> returnType = declaredMethod.getReturnType();
  64. System.out.print(returnType + "\t");
  65. //获取方法名
  66. String name = declaredMethod.getName();
  67. System.out.print(name);
  68. System.out.print("(");
  69. //获取参数类型
  70. Class[] parameterTypes = declaredMethod.getParameterTypes();
  71. String parameterName = "";
  72. Parameter[] parameters = declaredMethod.getParameters();
  73. if (!(parameterTypes == null && parameterTypes.length == 0)) {
  74. for (int i = 0; i < parameterTypes.length; i++) {
  75. for (int j=0;j<parameters.length;j++) {
  76. parameterName = parameters[j].getName();
  77. System.out.print(parameterName);
  78. }
  79. if (i == parameterTypes.length - 1) {
  80. System.out.print(parameterTypes[i].getName() +" "+ parameterName);
  81. break;
  82. }
  83. System.out.print(parameterTypes[i].getName()+" "+parameterName + ",");
  84. }
  85. System.out.print(")");
  86. }
  87. //获取异常
  88. Class<?>[] exceptionTypes = declaredMethod.getExceptionTypes();
  89. if (exceptionTypes.length > 0) {
  90. System.out.print(" throws ");
  91. for (int i = 0; i < exceptionTypes.length; i++) {
  92. String name1 = exceptionTypes[i].getName();
  93. if (i == exceptionTypes.length - 1) {
  94. System.out.print(name1);
  95. break;
  96. }
  97. System.out.print(name1 + ",");
  98. }
  99. }
  100. System.out.println();
  101. }
  102. }

五:Class类的运用(对对象的描述的类)

QQ截图20210109200720.png

六:加载配置文件的两种方式

  1. @Test
  2. public void Test02() throws IOException {
  3. /**
  4. * 读取配置文件的方式一,默认在moudle下
  5. * 通过流的方式读取文件
  6. * 优点:只要路径对,可以加载任意位置的文件
  7. */
  8. //创建配置文件对象
  9. Properties properties=new Properties();
  10. //获取配置文件流
  11. InputStream inputStream = new FileInputStream("src\\main\\resources\\jdbc1.properties");
  12. //加载配置文件
  13. properties.load(inputStream);
  14. /**
  15. * 读取配置文件的方式二
  16. * 使用ClassLoader
  17. * 缺点:默认加载的是src下的文件
  18. */
  19. ClassLoader classLoader = RelfectTest.class.getClassLoader();
  20. InputStream resourceAsStream = classLoader.getResourceAsStream("jdbc1.properties");
  21. properties.load(resourceAsStream);
  22. //获取配置文件的内容并打印
  23. String user = properties.getProperty("password");
  24. System.out.println(user);
  25. }