反射
什么是反射?
反射就是程序运行状态中,对于任意一个类,能够知道这个类的所有属性和方法,对于任意一个对象,能够调用方法/获取属性。
就是反射可以通过指定的类名来获取类的信息。
首先要知道一个知识点,类加载过程:
- 首先,一个.java文件经过编译成功后,得到一个.class文件
- 初始化操作的时候,会将这个.class文件通过类加载器加载到jvm中
- 加载到jvm中又分了好几个步骤,包括加载,连接和初始化
- 加载的时候,会再Java堆中创建一个java.lang.Class类的对象,这个Class对象代表着类的相关信息
为什么要学习反射?
参考链接:关于反射挺不错的讲解
反射的学习
其实就是对Class类和java.lang.reflect的学习
如何获取class对象
//1. 通过 Class.forName(String className) 来获取class对象
Class<?> clazz = Class.forName("Solution");
//2. 通过 类名.class获取class对象
Class<Solution> solutionClass = Solution.class;
//3. 通过 实例对象.getClass()来获取class对象
Solution solution = new Solution();
Class<? extends Solution> solutionClass1 = solution.getClass();
运行期间,一个类只能有一个Class对象产生
class Solution{
public void sayHello(){
System.out.println("hello");
}
public static void main(String[] args){
try {
Class<Solution> solutionClass = Solution.class;
Class<?> solution = Class.forName("Solution");
System.out.println(solution.hashCode());
System.out.println(solutionClass.hashCode());
} catch (Exception e) {
e.printStackTrace();
}
}
}
验证(输出结果):
685325104
685325104
java.lang.reflect包下的主要类库就是下面三个:
- Filed:可以使用get()和set()方法读取和修改Filed对象关联的字段
- Method:可以使用invoke()方法调用与Method对象关联的方法
- Constructor:可以使用Constructor创建对象
反射优缺点
- 优点:可扩展,在运行时加载类,更灵活
- 缺点:一系列解释性操作,通过jvm实现,性能开销大
反射应用场景
-
jdbc中连接数据库时候,反射加载驱动程序
Class.forNmae("com.mysql.jdbc.Driver");
-
Spring中 IOC容器根据配置文件信息 --> 获取类文件信息 --> 反射创建bean实例,并反射调用Set方法设置属性
-
SpringMVC自动识别前台传递过来的参数,自动组装成JavaBean,这也是通过反射来实现的
反射的Demo
详情见我另一篇博客:反射demo
-
通过反射调用方法
import java.lang.reflect.Method; class Solution{ public static void main(String[] args){ try { // 通过反射调用类的方法 // 获取class对象 Class<?> clazz = Class.forName("com.hou.study.Book"); // 使用java.lang.reflect包下的Method类库 Method method = clazz.getMethod("sayHello", String.class, int.class); // 使用invoke调用与method相关联的方法 method.invoke(clazz.newInstance(),"Java",20); } catch (Exception e) { e.printStackTrace(); } } } // 输出结果 // hello!,this book name is Javaand price is 20
-
通过反射设置属性
import java.lang.reflect.Field; class Solution{ public static void main(String[] args){ try { // 获取class对象 Class<?> clazz = Class.forName("com.hou.study.Book"); Object instance = clazz.newInstance(); // 此时用到了 java.lang.reflect 的 Filed类库 Field field = clazz.getDeclaredField("name"); // 设置取消权限检查,可以set field.setAccessible(true); field.set(instance,"Java"); System.out.println(instance); } catch (Exception e) { e.printStackTrace(); } } } // 输出结果 // Book{name='Java', price=0}
-
通过反射构造实例化对象
import java.lang.reflect.Constructor; class Solution{ public static void main(String[] args){ try { // 获取class对象 Class<?> clazz = Class.forName("com.hou.study.Book"); // 获取带参构造方法 用到了constructor类库 Constructor<?> constructor = clazz.getConstructor(String.class, int.class); Object java = constructor.newInstance("Java", 20); System.out.println(java); // Book{name='Java', price=20} // 获取无参构造方法 Constructor<?> constructor1 = clazz.getConstructor(); Object o = constructor1.newInstance(); System.out.println(o); // Book{name='null', price=0} } catch (Exception e) { e.printStackTrace(); } } }