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");