什么是反射
# 什么是反射
引入反射的概念之前,我们先看看为什么需要反射,用了有什么好处
# 引入反射之前
反射之中包含了一个“反”的概念,所以要想解释反射就必须先从“正”开始解释。一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化对象。--from MLDN 李兴华老师
我们创建一个对象,往往是使用先 import,再使用的方式,例如
import java.util.HashMap;
//……省略其他代码
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
2
3
4
5
如果后续有需求,要改成 LinkedHashMap
,那么就得改动代码
import java.util.LinkedHashMap;
//……省略其他代码
Map<Integer, Integer> map = new LinkedHashMap<>();
2
3
如果后续又有需求,要改成其他类,那么每有一个需求,都要重新改动一次……
或许有人要问了,真有这样的需求吗?有的,例如 JDBC 里,我们连接数据库需要一个驱动类
class.forName("com.mysql.jdbc.Driver");
//获取与数据库连接的对象-Connetcion
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/learn", "root", "root");
//获取执行sql语句的statement对象
statement = connection.createStatement();
//执行sql语句,拿到结果集
resultSet = statement.executeQuery("SELECT * FROM users");
2
3
4
5
6
7
8
9
10
当更换数据库的时候,就得修改驱动类,换成其他数据库厂家的驱动类。改代码是麻烦的,需要重新编译和测试,常常是将这些需要频繁改动的地方,写到一个配置文件里,这样,我们就就不用修改代码了,而是通过修改配置的方式去实现变化。
有人可能会问:“那还是要改啊,我改代码也很快啊,你改配置不也是要改吗”。
其实不一样的,我举个例子:
- 三歪写了一个 JDBC 组件,把各种配置都写死在代码上,比如上面的 driver/username/数据库连接数等等。现在三歪不干了,要跑路了。
- 敖丙来接手三歪的代码,敖丙刚开始接手项目,公司说要换数据库。敖丙给领导说:这玩意,我改改配置就好了,几分钟完事。
- 敖丙找了半天都没找到配置的地方,由于三歪写的代码又臭又烂,找了半天才找到入口和对应的位置。
- 改代码的风险要比改配置大,即便不知道代码的实现都能通过改配置来完成要做的事。
修改为读取配置文件后,代码类似这样:
//获取配置文件的读入流
InputStream inputStream = UtilsDemo.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(inputStream);
//获取配置文件的信息
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//加载驱动类
Class.forName(driver);
2
3
4
5
6
7
8
9
10
11
12
13
14
也就是说,应用程序在编译的时候,是不知道到底使用的是什么类的,只要到了运行的时候,才会动态的把类加载进内存(参考第 14 行,就是加载类进来),并使用其方法,这通过正射是做不到的,也是反射的一个优点:解耦
# 什么是反射
在 Java 中,反射(Reflection)是指程序在运行期可以拿到一个对象的所有信息。反射非常重要,没有反射,也就没有后面我们要学习的框架了
框架:半成品的代码。可以在框架的基础上进行软件开发,简化编码,这里不展开,后续我们学习 Spring 的时候,它就是通过反射实例化对象的:当程序启动时,Spring 会读取配置文件
applicationContext.xml
,并解析出里面所有的标签实例化到IOC
容器中。后面学习的日志框架也是一样的,Commons Logging 总是优先使用 Log4j,只有当 Log4j 不存在时,才使用 JDK 的 logging。
反射的用处举例:其实,相信大部分读者都至少享受过反射带来的好处。例如在 IDE 中定义了一个字符串变量 c
,当输入 c.
时,IDE 会自动提示 String 类型的方法。这就是反射的一个应用:获取该类的方法。
String c = "abc";
c.toString();
2
关于反射的一些专业的说法:在 Gilad Bracha 与 David Ungar 合作的论文是这样说的
Reflective language architectures may be characterized in terms of their support for:
- Introspection. The ability of a program to examine its own structure.
- Self-modification. The ability of a program to change its own structure.
- Execution of dynamically generated code. The ability to execute program fragments that are not statically known. This is a special case of 2.
- Intercession. The ability to modify the semantics of the underlying programming language from within the language itself (the term intercession is sometimes used in a broader sense in parts of the literature, but we adopt the narrower definition of intercession given here, based on [18]).