什么是反射?
Java核心技术卷一中这么写到:
反射库(reflection library)提供了一个丰富且精巧的工具集,可以用来编写动态操纵Java代码的程序。使用反射,Java可以支持用户界面生成器,对象关系映射器以及很多其他需要动态查询能力的开发工具。
????????????????不懂
”反“不懂,那我们从“正”开始
一般情况下我们怎么用类的,首先实例化一个类对象,在对这个类对象进行操作
Apple apple = new Apple(); //直接初始化,「正射」 apple.setPrice(4);
我们使用一个对象,再利用他的各个成分叫“正”
那么“反”其道而行之,不实例化一个类,就使用他的成分
Class类
但是在运用反射之前,我们先来理解Class类
Class类是一个实实在在的类,存在JDK的java.lang包内,也是继承Object类的,那他到底是什么东西?
在深入理解Java虚拟机中有这么一段话:
类加载的过程:
1.通过一个类的全限定名来获取定义此类的二进制字节流
2.将这个字节流所代表的静态储存结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问
毫无疑问第三点解答了,用我的话说就是它可以通过Class类对象来访问你想要访问的对象,及其方法举个例子(下图片1是韩顺平java的):
(两张图结合看)
我们计算机运行的三个阶段在编译器把.java文件编译成.class字节码文件后就要传入JVM中类加载,上图中的Cat对象在实例化后就在堆中创建了一个Class类对象,里面数组有Field[],Constructor[],Method[](这三个方法之后会介绍)。
我们一开始说的“正”,在我们实例化Cat的时候,他就会自主的Class类对象中找相应的属性去使用。
原来我们的“正”也要用到Class类对象!!!!!!!!
那么“反”的真正意义就是直接用Class对象去使用像访问对象的成员
比如用Class对象直接去用Cat.hi();
怎么用呢?
我们先看看Class的常用方法
Class类常用方法:
注意画红线部分,跟上面我们提到的Class类对象中的数组好像
这三个方法就是储存相应成员的!!
比如getConsructors是获取到Cat的构造方法
getMethod是获取到Cat中的某个方法
好了现在我们开始获取Class类对象吧
我这里列举四种
第一种:
已知类的全类名路径,运用forName方法(常用)
第二种:
通过类加载器,classLoader.loadClass()方法
第三种:
getClass方法(虽然先实例化了Car)
第四种:
在知道类的情况下可以使用:
然后通过Class对象获取其他成员
newInstance()是放回apple实例
invoke()利用了上面getMethod(“setPrice”,int.class)获取到的方法设置appleObj对象的属性Price=14;
反射是什么?
反射就是通过Class类去获取对象的接口,字段和方法
应用在什么场景?
我们一般写代码很少接触,但是不代表没有,正因为反射,我们才能轻松的使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。
这些框架中也大量使用了动态代理,而动态代理的实现也依赖反射。
反射优点:
让我们操作代码更加灵活
缺点:
在运行的时候直接能获取类中各种成员,不安全
我当时有个疑问
第一种获取Class对象和第四种获取Class对象有什么区别?为什么第一种常用?
查询资料大概是说forName()是在运行时动态获取的,而第四种.class是在编译时候就获取了
举例:数据库连接
import java.sql.Connection; import java.sql.DriverManager; import java.util.Properties; public class DatabaseConnection { public static Connection getConnection() throws Exception { Properties props = new Properties(); props.load(new FileInputStream("database.properties")); String driver = props.getProperty("jdbc.driver"); String url = props.getProperty("jdbc.url"); String user = props.getProperty("jdbc.user"); String password = props.getProperty("jdbc.password"); // 动态加载数据库驱动类,类似这样插件的类要在运行的时候才能够得到,运用forName方法才能够得到Class类对象 Class.forName(driver); // 建立数据库连接 return DriverManager.getConnection(url, user, password); } public static void main(String[] args) { try { Connection connection = getConnection(); System.out.println("Database connection successful!"); } catch (Exception e) { e.printStackTrace(); } } }