每个类都有⼀个 Class 对象,包含了与类有关的信息。当编译⼀个新类时,会产⽣⼀个同名的 .class⽂件,该⽂件内容保存着 Class 对象。
类加载相当于 Class 对象的加载,类在第⼀次使⽤时才动态加载到 JVM 中。也可以使⽤Class.forName("com.mysql.jdbc.Driver") 这种⽅式来控制类的加载,该⽅法会返回⼀个 Class 对 象。
反射可以提供运⾏时的类信息,并且这个类可以在运⾏时才加载进来,甚⾄在编译时期该类的 .class 不存在也可以加载进来。
Class 和 java.lang.reflect ⼀起对反射提供了⽀持,java.lang.reflect 类库主要包含了以下三个类:
- Field :可以使⽤ get() 和 set() ⽅法读取和修改 Field 对象关联的字段;
- Method :可以使⽤ invoke() ⽅法调⽤与 Method 对象关联的⽅法;
- Constructor :可以⽤ Constructor 的 newInstance() 创建新的对象。
反射的优点:
- 可扩展性 :应⽤程序可以利⽤全限定名创建可扩展对象的实例,来使⽤来⾃外部的⽤户⾃定义类。
- 类浏览器和可视化开发环境 :⼀个类浏览器需要可以枚举类的成员。可视化开发环境(如 IDE)可以从利⽤反射中可⽤的类型信息中受益,以帮助程序员编写正确的代码。
- 调试器和测试⼯具 : 调试器需要能够检查⼀个类⾥的私有成员。测试⼯具可以利⽤反射来⾃动地调⽤类⾥定义的可被发现的 API 定义,以确保⼀组测试中有较⾼的代码覆盖率。
反射的缺点:
尽管反射⾮常强⼤,但也不能滥⽤。如果⼀个功能可以不⽤反射完成,那么最好就不⽤。在我们使⽤反射技术时,下⾯⼏条内容应该牢记于⼼。
- 性能开销 :反射涉及了动态类型的解析,所以 JVM ⽆法对这些代码进⾏优化。因此,反射操作的效率要⽐那些⾮反射操作低得多。我们应该避免在经常被执⾏的代码或对性能要求很⾼的程序中使 ⽤反射。
- 安全限制 :使⽤反射技术要求程序必须在⼀个没有安全限制的环境中运⾏。如果⼀个程序必须在有安全限制的环境中运⾏,如 Applet,那么这就是个问题了。
- 内部暴露 :由于反射允许代码执⾏⼀些在正常情况下不被允许的操作(⽐如访问私有的属性和⽅法),所以使⽤反射可能会导致意料之外的副作⽤,这可能导致代码功能失调并破坏可移植性。反 射代码破坏了抽象性,因此当平台发⽣改变的时候,代码的⾏为就有可能也随着变化。