反射是在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性。

特点:

获取Class对象的常用方式

  1. Class.forName("类的全限定名"):将字节码文件载入内存,返回Class对象。
  2. 类名.class:通过类名的属性class获取。
  3. 对象.getClass():getClass()方法返回表示该对象的类的Class对象。
  4. 类名[].class:获取数组类的Class对象。
// 1. 通过类的全路径名获取Class对象
Class clazz = Class.forName("java.lang.String");
// 2. 通过类名.class获取Class对象
Class clazz2 = String.class;
// 3. 通过对象的getClass()方法获取Class对象
String str = "hello";
Class clazz3 = str.getClass();
// 4. 通过类加载器获取Class对象
ClassLoader classLoader = String.class.getClassLoader();
Class clazz4 = classLoader.loadClass("java.lang.String");
// 5. 基本数据类型的包装类都有一个TYPE属性
Class clazz5 = Integer.TYPE;
// 6. void关键字也有一个TYPE属性
Class clazz6 = Void.TYPE;
// 7. 通过数组的getClass()方法获取Class对象
int[] arr = new int[10];
Class clazz7 = arr.getClass();
// 9. 通过Class对象的getComponentType()方法获取数组的元素类型
Class clazz9 = clazz8.getComponentType();

反射调用

Class clz = Apple.class;
Method setPriceMethod = clz.getMethod("setPrice", int.class);
Constructor constructor = clz.getConstructor();
constructor.setAccessible(true);
Object appleObj = constructor.newInstance();
setPriceMethod.invoke(appleObj, 14); // 反射调用
Method getPriceMethod = clz.getMethod("getPrice");
Object price = getPriceMethod.invoke(appleObj); // 反射调用
System.out.println(price); // 14
System.out.println(clz.getName()); // com.keyon.reflect.Apple
System.out.println(clz.getSimpleName()); // Apple
System.out.println(clz.getPackage()); // package com.keyon.reflect
System.out.println(clz.getSuperclass()); // class java.lang.Object

反射的原理

  1. 类在被加载时,会产生一个Class对象,该对象包含了该类的所有信息。
  2. 通过Class对象可以获取到该类的元数据信息,包括:构造器,方法,字段等等。
  3. 通过Constructor对象可以动态构造类的对象。
  4. 通过Method对象可以动态调用对象的方法。
  5. 通过Field对象可以动态读取/修改对象的字段。 所以反射最重要的对象就是Class,通过Class对象可以知道一个类的全部信息,进而操作这个类。

Class.forName() 获取类实例