Java 知识点 —— 反射

一、什么是反射

java 运行时,识别对象和类的信息的传统方式是 RTTI,它要求我们再编译阶段就确定所以对象的信息,比如,如何去构造它,参数是什么...而反射机制则是在运行阶段去确认这些信息。

二、反射的实现

简单的例子,假设我们有一个类 ReflectModel:

 1 package SSMTest;
 2 import static MyTools.PrintTools.*;
 3 
 4 public class ReflectModel {
 5 
 6     private String name;
 7     
 8     public ReflectModel() {}
 9     
10     public ReflectModel(String name) {
11         this.name = name;
12     }
13     public void HelloWorld() {
14         println("Hello World");
15     }
16     public void NameSay() {
17         println(name + "say Hello World");
18     }
19 }

一般情况下,我们创建该类的实例是在编译阶段就确认好的:

 1 package SSMTest;
 2 
 3 public class ReflectImpl {
 4     public static void main(String args[]) {
 5         ReflectModel reflectModel1 = new ReflectModel();
 6         ReflectModel reflectModel2 = new ReflectModel("Li ");
 7         reflectModel1.HelloWorld();
 8         reflectModel2.NameSay();
 9         
10     }
11 }
12 /*output
13 Hello World
14 Li say Hello World
15 */

但是,假如我希望能够在运行的时候,再去决定如何创建这个类,该如何实现?这里可以使用 java 的反射机制:

 1 package SSMTest;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 
 5 public class ReflectImpl1 {
 6 
 7     public static void main(String[] args) {
 8         ReflectModel model1 = null,model2 = null;
 9         try {
10             model1 = (ReflectModel)Class.forName("SSMTest.ReflectModel").newInstance();
11             model1.HelloWorld();
12         } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
13             // TODO Auto-generated catch block
14             e.printStackTrace();
15         }
16         try {
17             model2 = (ReflectModel)Class.forName("SSMTest.ReflectModel").getConstructor(
18                     String.class).newInstance("Li");
19             model2.NameSay();
20         } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
21                 | NoSuchMethodException | SecurityException | ClassNotFoundException e) {
22             // TODO Auto-generated catch block
23             e.printStackTrace();
24         }
25         
26     }
27 
28 }
29 /*output
30 Hello World
31 Lisay Hello World
32 */

Class.fornName() 方法可以帮我们根据类的全名去找到这个类的加载器,然后通过加载器的 newInstance() 方法创建一个对象,如果是带参数的构造器,则使用加载器的 getConstructor({参数类型}.class)找到对应构造函数的加载器,然后再用 newInstance() 方法创建一个对象。

如此一来我们便实现了在运行过程中去确定类的实现方式。那么,既然类的初始化可以在运行时实现,类的方法是否也能在运行时去找到它并且进行调用?以下是实现方式:

 1 package SSMTest;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5 
 6 public class ReflectImpl2 {
 7 
 8     public static void main(String[] args) {
 9         ReflectModel model1 = null;
10         Object returnObj = null;
11         try {
12             model1 = (ReflectModel)Class.forName("SSMTest.ReflectModel").newInstance();
13         } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
14             // TODO Auto-generated catch block
15             e.printStackTrace();
16         }
17         try {
18             Method method = ReflectModel.class.getMethod("HelloWorld");
19             returnObj = method.invoke(model1);
20         } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
21             // TODO Auto-generated catch block
22             e.printStackTrace();
23         }
24         
25     }
26 
27 }
28 /*output
29 Hello World*/

如果是带参数的方法,例如参数是 String,则将 18 行修改为:

Method method = ReflectModel.class.getMethod("HelloWorld",String.class);

同样第 19 行修改为

returnObj = method.invoke(model1,"args");

 

posted @ 2018-09-28 15:04  crazy_runcheng  阅读(188)  评论(0编辑  收藏  举报