反射

一、反射机制

程序在执行期间用Reflection获得类的内部信息,操作对象的属性及方法
加载完类之后,在堆中产生了一个Class类型的对象,这个对象包含了完整的类结构信息,通过类的对象得到类的结构
未命名文件.png

  • 反射的优缺点:

    • 优点:动态的创建和使用对象
    • 缺点:基本是解释实行,对执行速度有影响

      二、反射相关的主要类

      Class:类,其对象表示某个类加载后在堆中的对象
      Method:方法
      Field:成员变量
      Constructor:构造方法
      1. public class Reflection1 {
      2. public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
      3. // Properties类读写配置文件
      4. Properties properties = new Properties();
      5. properties.load(new FileInputStream("src\\re.properties"));
      6. String method = properties.get("method").toString();
      7. String classfullpath = properties.get("classfullpath").toString();
      8. System.out.println(classfullpath + " " + method);
      9. // 使用反射机制解决
      10. // (1) 加载类,返回Class类型的对象cls
      11. Class cls = Class.forName(classfullpath);
      12. // (2) 通过cls得到加载的类java30.reflection.Cat的对象
      13. Object o = cls.newInstance();
      14. System.out.println(o.getClass()); // class java30.reflection.Cat
      15. // (3) 通过cls得到加载的类的java30.reflection.Cat的此时为"hi"方法的对象
      16. // 即在反射中,把方法视为对象
      17. Method method1 = cls.getMethod(method);
      18. // (4) 通过method1调用方法:即通过方法对象来实现调用方法
      19. method1.invoke(o); // 反射机制 方法.invoke(对象)
      20. // java.lang.reflect.Field代表类的成员变量,Field对象表示某个类的成员变量
      21. // getField不能得到私有的属性
      22. Field nameField = cls.getField("age");
      23. System.out.println(nameField.get(o)); // 反射:成员变量对象.get(对象)
      24. //
      25. Constructor constructor = cls.getConstructor(); // ()中可以指定构造器参数类型,返回无参构造器
      26. System.out.println(constructor); // public java30.reflection.Cat()
      27. Constructor constructor1 = cls.getConstructor(String.class);//String.class是String类的Class对象
      28. System.out.println(constructor1); // public java30.reflection.Cat(java.lang.String)
      29. }
      30. }

      三、反射调用优化

      关闭访问检查
      Method、Field和Constructor对象都有setAccessible()方法,作用是启动和禁用访问安全检查的开关,true表示使用反射的对象时取消访问检查,提高反射的效率,false表示反射的对象执行访问检查

      四、Class类

      ![%YLNTUAS_VVE68I0FLLZ17.png

      4.1 简介

      Class类继承Object类,不是new创建的,是系统创建的
      某个类的Class类对象,在内存中只有一份,类只加载一次
      通过Class对象可以得到一个类的完成结构
      Class对象存放在堆中
      类的字节码二进制数据放在方法区
      外部类、内部类、接口、数组、枚举、注解(annotation)、基本数据类型和void都有Classs对象

      4.2 常用方法

      1. public class Class02 {
      2. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
      3. String classAllPath = "java30.reflection.Car";
      4. // 获取到Car类的Class对象
      5. // <?>表示不确定的Java类型 可以去掉
      6. Class<?> cls = Class.forName(classAllPath);
      7. System.out.println(cls); // class java30.reflection.Car
      8. System.out.println(cls.getClass()); // 运行类型 class java.lang.Class
      9. // 得到包名
      10. System.out.println(cls.getPackage().getName()); // 包名
      11. // 类名
      12. System.out.println(cls.getName());
      13. // 用cls创建对象实例
      14. Car car = (Car) cls.newInstance();
      15. System.out.println(car);
      16. // 通过反射获取属性
      17. Field brand = cls.getField("brand"); // 不能是私有属性
      18. System.out.println(brand.get(car));
      19. // 给属性赋值
      20. brand.set(car, "che");
      21. System.out.println(brand.get(car));
      22. // 所有属性
      23. Field[] fields = cls.getFields();
      24. for (Field f: fields) {
      25. System.out.println(f.getName());
      26. }
      27. }
      28. }
      其它方法:
  • Class[] getInterfaces() 获取当前Class对象的接口

  • ClassLoader getClassLoader() 返回该类的类加载器
  • Class getSuperclass() 超类的Class
  • Constructor[] getConstructors() 某些Constructor对象的数组
  • Field[] getDeclaredFields() Field对象的一个数组
  • Method getMethod(String name, Class paramTypes) 返回一个Method对象

    4.3 获取Class类对象

  1. 编译阶段 Class.forName() 多用于配置文件,读取类全路径,加载类
  2. Class类阶段 类.class
  3. 运行阶段 对象.getClass()
  4. 类加载器得到Class对象
  5. 基本数据(int, char, boolean, float…) 基本数据类型.class
  6. 基本数据类型对应的包装类 包装类.TYPE

    1. public class GetClass {
    2. public static void main(String[] args) throws ClassNotFoundException {
    3. // 1. Class.forName
    4. String classAllPath = "java30.reflection.Car"; // 通过配置文件读取
    5. Class<?> aClass = Class.forName(classAllPath);
    6. System.out.println(aClass);
    7. // 2. 类.class 用于参数传递
    8. System.out.println(Car.class);
    9. // 3. 对象.getClass() 有对象实例
    10. Car car = new Car();
    11. Class aClass1 = car.getClass();
    12. System.out.println(aClass1);
    13. // 4. 通过类加载器获取到类的Class对象
    14. // 4.1 先得到类加载器
    15. ClassLoader classLoader = car.getClass().getClassLoader();
    16. // 4.2 通过类加载器得到Class对象
    17. Class aClass2 = classLoader.loadClass(classAllPath);
    18. System.out.println(aClass2);
    19. // 5. 基本数据得到Class对象
    20. Class<Integer> integerClass = int.class;
    21. Class<Character> characterClass = char.class;
    22. Class<Boolean> booleanClass = boolean.class;
    23. System.out.println(integerClass); // int
    24. // 6. 包装类 .TYPE得到Class类对象
    25. Class<Integer> type1 = Integer.TYPE;
    26. Class<Character> type2 = Character.TYPE;
    27. System.out.println(type1); // int
    28. }
    29. }

    五、类加载

    5.1 简介

  7. 静态加载:编译时加载相关的类 依赖性强 当创建对象(new)、子类被加载,父类也加载、调用类中的静态成员时

动态加载:运行时需要加载的类 依赖性低 通过反射

  1. 类加载过程图

未命名文件.png

5.2 类加载各阶段

5.2.1 加载

由类加载器完成,将字节码从class文件,jar包等数据源转化为二进制字节流加载到内存中,并生成一个Class对象

5.2.2 连接

将类的二进制数据合并到JRE中

5.2.2.1 验证
  1. 确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机安全
  2. 包括文件格式验证、元数据验证、字节码验证和符号引用验证
  3. -Xverify:none参数关闭大部分的类验证措施,缩短虚拟机类加载的时间

    5.2.2.2 准备

    JVM对静态变量分配内存并默认初始化(默认为0,0L,null等)。这些变量使用的内存都在方法区中分配

    5.2.2.3 解析

    JVM将常量池内的符号引用替换为直接引用

    5.2.3 初始化

    JVM对类进行初始化,主要针对静态成员

  4. 初始化阶段,才真正开始执行类中定义的Java程序,此阶段是执行()方法的过程

  5. ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值和静态代码块中的语句,并进行合并

    1. public class ClassLoad {
    2. public static void main(String[] args) {
    3. /*
    4. clinit() {
    5. System.out.println("B静态代码块被执行");
    6. num = 300;
    7. num = 100; //这里会合并
    8. }
    9. */
    10. // B b = new B();
    11. System.out.println(B.num);
    12. }
    13. }
    14. class B {
    15. static {
    16. System.out.println("B静态代码块被执行");
    17. num = 300;
    18. }
    19. static int num = 100;
    20. public B() {
    21. System.out.println("B() 构造器被执行");
    22. }
    23. }

    六、通过反射获取类的结构信息

    ```java public class ReflectionUtils { public static void main(String[] args) {

    } @Test public void method1() throws ClassNotFoundException, NoSuchMethodException {

    1. // Class对象
    2. Class<?> personClass = Class.forName("java30.reflection.Person");
    3. // 全类名
    4. System.out.println(personClass.getName()); // java30.reflection.Person
    5. // 简单类名
    6. System.out.println(personClass.getSimpleName()); // Person
    7. // public修饰的属性,包括本类和父类的
    8. Field[] fields = personClass.getFields();
    9. for (Field field : fields) {
    10. System.out.println(field.getName()); // name a
    11. }
    12. // 本类中所有属性
    13. Field[] declaredFields = personClass.getDeclaredFields();
    14. for (Field declaredField : declaredFields) {
    15. System.out.println(declaredField.getName()); // name age josalary
    16. }
    17. // public修饰的方法 本类+父类 父类的父类..
    18. Method[] methods = personClass.getMethods();
    19. for (Method method : methods) {
    20. System.out.println(method.getName());
    21. }
    22. // 本类所有方法
    23. Method[] declaredMethods = personClass.getDeclaredMethods();
    24. for (Method declaredMethod : declaredMethods) {
    25. System.out.println(declaredMethod.getName());
    26. }
    27. // public修饰的构造器
    28. Constructor<?>[] constructors = personClass.getConstructors();
    29. for (Constructor<?> constructor : constructors) {
    30. System.out.println(constructor.getName());
    31. }
    32. // 本类中所有构造器
    33. Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
    34. for (Constructor<?> declaredConstructor : declaredConstructors) {
    35. System.out.println(declaredConstructor.getName()); // 只有名字,没有参数列表
    36. // 返回修饰符
    37. int modifiers = declaredConstructor.getModifiers();
    38. // 返回参数类型数组
    39. Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
    40. }
    41. // 包信息
    42. System.out.println(personClass.getPackage()); // package java30.reflection
    43. // 父类class对象
    44. Class<?> superclass = personClass.getSuperclass();
    45. System.out.println(superclass); // class java30.reflection.A
    46. // 返回接口信息
    47. Class<?>[] interfaces = personClass.getInterfaces();
    48. for (Class<?> anInterface : interfaces) {
    49. System.out.println(anInterface);
    50. }
    51. // 形式返回注解信息
    52. Annotation[] annotations = personClass.getAnnotations();
    53. for (Annotation annotation : annotations) {
    54. System.out.println(annotation); // @java.lang.Deprecated()
    55. }
    56. // 获取所有public修饰的方法,包括本类以及父类的
    57. Method[] declaredMethods1 = personClass.getDeclaredMethods();
    58. for (Method method : declaredMethods1) {
    59. System.out.println(method.getName());
    60. // 该方法的访问修饰符
    61. System.out.println(method.getModifiers());
    62. // 该方法返回类型
    63. System.out.println(method.getReturnType());
    64. // 形参数组
    65. Class<?>[] parameterTypes = method.getParameterTypes();
    66. for (Class<?> parameterType : parameterTypes) {
    67. System.out.println(parameterType);
    68. }
    69. }

    } @Test public void method2() throws ClassNotFoundException {

    1. // Class对象
    2. Class<?> personClass = Class.forName("java30.reflection.Person");
    3. // 本类中所有属性
    4. Field[] declaredFields = personClass.getDeclaredFields();
    5. for (Field declaredField : declaredFields) {
    6. System.out.println(declaredField.getName()); // name age josalary
    7. // int形式返回修饰符 默认0,public 1,private 2,protected 4 static 8 final 16 public static 9
    8. System.out.println(declaredField.getModifiers());
    9. // 属性的类型
    10. System.out.println(declaredField.getType());
    11. }

    } } class A { public String a; public void m5() {} public A() {} public A(String name) {} } interface IA {} interface IB {}

@Deprecated class Person extends A implements IA, IB { public String name; protected int age; String job;//默认 private double salary;

  1. public Person() {}
  2. public Person(String name, int age, String job, double salary) {
  3. this.name = name;
  4. this.age = age;
  5. this.job = job;
  6. this.salary = salary;
  7. }
  8. public void m1() {}
  9. protected void m2() {}
  10. void m3() {}
  11. private void m4() {}

}

  1. <a name="PbkAY"></a>
  2. ## 七、反射创建对象
  3. ```java
  4. public class ReflectCreateInstance {
  5. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
  6. Class<?> uClass = Class.forName("java30.reflection.U");
  7. // 无参构造器创建实例
  8. Object o = uClass.newInstance();
  9. System.out.println(o);
  10. // public有参构造器创建实例
  11. Constructor<?> constructor = uClass.getConstructor(String.class);
  12. Object aaa = constructor.newInstance("aaa");
  13. System.out.println(aaa);
  14. // 非public有参构造器创建实例
  15. Constructor<?> declaredConstructor = uClass.getDeclaredConstructor(int.class, String.class);
  16. // 爆破 使用反射访问private的构造器、方法、属性
  17. declaredConstructor.setAccessible(true);
  18. Object c = declaredConstructor.newInstance(11, "c");
  19. System.out.println(c); // U{age=11, name='c'}
  20. }
  21. }
  22. class U {
  23. private int age = 10;
  24. private String name = "名字";
  25. public U() {
  26. }
  27. public U(String name) {
  28. this.name = name;
  29. }
  30. private U(int age, String name) {
  31. this.age = age;
  32. this.name = name;
  33. }
  34. @Override
  35. public String toString() {
  36. return "U{" +
  37. "age=" + age +
  38. ", name='" + name + '\'' +
  39. '}';
  40. }
  41. }

八、反射访问类中的成员

8.1 访问属性

  1. public class ReflectAccessProperty {
  2. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
  3. Class<?> u1Class = Class.forName("java30.reflection.U1");
  4. Object o = u1Class.newInstance();
  5. System.out.println(o.getClass()); // class java30.reflection.U1
  6. // 反射得到age对象
  7. Field age = u1Class.getField("age");
  8. age.set(o,20);
  9. System.out.println(o); // U1{age=20,name=null}
  10. System.out.println(age.get(o)); // 返回age属性的值 20
  11. // 反射得到name
  12. Field name = u1Class.getDeclaredField("name");
  13. // 爆破
  14. name.setAccessible(true);
  15. name.set(o,"d");
  16. System.out.println(o); // U1{age=20,name=d}
  17. }
  18. }
  19. class U1 {
  20. public int age = 10;
  21. private static String name;
  22. public U1() {
  23. }
  24. @Override
  25. public String toString() {
  26. return "U1{" +
  27. "age=" + age + ",name=" + name +
  28. '}';
  29. }
  30. }

8.2 访问方法

  1. public class ReflectAccessMethod {
  2. public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
  3. Class<?> u2Class = Class.forName("java30.reflection.U2");
  4. Object o = u2Class.newInstance();
  5. Method h = u2Class.getDeclaredMethod("h", String.class);
  6. h.invoke(o,"ddd");
  7. Method s = u2Class.getDeclaredMethod("s", int.class, String.class, char.class);
  8. s.setAccessible(true); //s是private的
  9. System.out.println(s.invoke(o,30,"sss",'d'));
  10. // s 方法私有 也能传入null
  11. System.out.println(s.invoke(null,30,"sss",'d'));
  12. }
  13. }
  14. class M {
  15. }
  16. class U2 {
  17. public int age = 10;
  18. private static String name;
  19. public U2() {
  20. }
  21. public M m1() {
  22. return new M();
  23. }
  24. public static String s(int n, String s, char c) {
  25. return n+" "+s+" "+c;
  26. }
  27. public void h(String s) {
  28. System.out.println(s);
  29. }
  30. @Override
  31. public String toString() {
  32. return "U1{" +
  33. "age=" + age + ",name=" + name +
  34. '}';
  35. }
  36. }