设计模式中,有很多地方会用到反射机制,下面通过代码来讲解反射机制。
一个实体类如下:
1 package springBootExample.example.application; 2 3 public class ReflectApp { 4 5 private String name; 6 7 public String title; 8 9 public ReflectApp() {10 11 }12 13 public ReflectApp(String name, String title) {14 this.name = name;15 this.title = title;16 }17 18 public String getName() {19 return name;20 }21 22 public void setName(String name) {23 this.name = name;24 }25 26 public String getTitle() {27 return title;28 }29 30 public void setTitle(String title) {31 this.title = title;32 }33 34 public void printString(String name, String title) {35 System.out.println("name = " + name + "title = " + title);36 }37 38 public void printString() {39 System.out.println("name = " + name + " title = " + title);40 }41 42 }
其实一个类说的详细点主要是由以下几个部分组成:Class = Field + Constructor + Method (这里说主要由这几个组成,其实还可以有注解Annotation之类生僻的概念,不做讨论了)
Field 就是常说的 属性+属性值,这里其实可以这样理解,属性主要是针对类的,属性值主要是针对对象的。为了方便解释反射,直接在类中定义了默认初始值,让类也具备了属性值。
Constructor 包括了有参构造和无参构造...这些构造方法。
Method就是那些有参,无参,又返回,无返回的各类方法。
一般,我们直接利用类new一个对象出来,现在我们用反射,看怎么新建一个对象
1 // 通过类名称实例化类 2 @Test 3 @Ignore 4 public void testNewClass() throws InstantiationException, IllegalAccessException, ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException{ 5 //方式1 6 // Class clazz = ReflectApp.class; //获得类的字节码 7 // ReflectApp app = (ReflectApp) clazz.newInstance(); 8 9 //方式2 类名称所在的路径10 String className = "springBootExample.example.application.ReflectApp";11 ReflectApp app = (ReflectApp) Class.forName(className).newInstance();12 13 app.setName("hu");14 app.setTitle("hoojjack");15 app.printString();16 17 /**18 * 以上是通过类名获取,下面将通过实例重新获取类名,这正是反射的强大之处19 * 20 */21 Class instance = app.getClass(); // 获得类的字节码,通过构造方法实例化一个类对象22 Constructor con = instance.getDeclaredConstructor(String.class,String.class);23 ReflectApp app2 = con.newInstance("hoojjack","hu");24 app2.printString();25 }
利用反射获取实例化对象的属性以及属性值:
1 @Test 2 public void testReflectField () throws InstantiationException, IllegalAccessException { 3 Class clazz = ReflectApp.class; 4 Field [] fields =clazz.getDeclaredFields(); //可以获得所有属性 5 // 实例化一个对象,并对属性赋值,以便后面获得对象属性时能得到值 6 ReflectApp app = (ReflectApp) clazz.newInstance(); 7 app.setName("hujianjie"); 8 app.setTitle("hoojjack"); 9 // Field [] fields =clazz.getFields(); //仅获取被声明的public属性10 for (Field field : fields) {11 System.out.print(field.getName());12 //如果是私有属性,必须设置访问权限才可以访问13 if(!field.isAccessible()) { //对所有的属性来说isAccessible初始都是false,此处可以不用判断14 field.setAccessible(true); //属性是私有的时候,必须设置为true才能访问15 System.out.println(" field value : "+field.get(app));16 }17 }18 }
利用反射获取实例化对象的方法:
@Test public void testReflectMethod () throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class clazz = ReflectApp.class; Method [] methods = clazz.getDeclaredMethods(); ReflectApp app = (ReflectApp) clazz.newInstance(); app.setName("hujianjie"); app.setTitle("hoojjack"); // 反射调用实例化对象的方法 for (Method method : methods) { if(method.getParameterCount()>=2) { method.invoke(app, "hu","jack"); }else if (method.getParameterCount() == 0){ method.invoke(app); } } }
输出结果:
name = hutitle = jackname = hujianjie title = hoojjack