反射
简单的介绍反射的使用。
为什么要使用反射
-
获取私有的属性方法,属性
-
当不确定类的类型的使用
反射的使用
新建一个java项目,创建一个Person
类,有name
,sex
,age
三个属性,同时,有一个私有的构造函数和两个个共有构造函数。 添加set和get方法,toString方法。
具体代码如下:
package com.shxzhlxrr.reflect.vo;public class Person { private String name; private String sex; private int age; public Person(){ } @SuppressWarnings("unused") private Person(String name){ this.name = name; } public Person(String name ,String sex,int age){ this.name = name; this.sex = sex; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]"; }}
获取私有构造函数,创建对象
第一步,我们需要先加载Person
类,使用Class.forName
方法加载,或返回一个Class
对象,我们用变量cla
保存。
通过cla
的getDeclaredConstructor
构造方法,我们可以获取类的声明的构造函数,不管是私有的,还是共有的,都可以获取到。 因为我们的私有构造方法需要传入一个字符串类型的name
,所以我们需要传入一个String.class
,不传的话,会去获取无参构造函数。 我们会获取到一个java.lang.reflect.Constructor
对象,用变量cons
进行保存。
通过cons
的setAccessible
传入true
我们可以对私有的构造方法进行访问。
最后我们可以通过newInstance
方法获取到一个Person
的实例化对象,设置名字为张三
。为了验证我们的名字是否设置成功,我们 可以打印实例化对象,如下所示,我们看到,我们的名字已经正确的设置了。
Person [name=张三, sex=null, age=0]
完整的测试代码如下所示:
public void testPrivateConstructor(){ try { //加载类 Class cla = Class.forName("com.shxzhlxrr.reflect.vo.Person"); Constructor cons = cla.getDeclaredConstructor(String.class); cons.setAccessible(true); Object obj = cons.newInstance("张三"); System.out.println(obj); } catch (Exception e) { e.printStackTrace(); } }
同理,获取私有的方法和属性是一样的,下面只罗列代码。
获取私有的方法,并调用
添加一个私有的方法say
打印出姓名。
私有构造方法say
如下:
private void say(){ System.out.println("我的名字是:"+this.name); }
测试方法如下:
public void testPrivateMethodSay(){ try { //加载类 Class cla = Class.forName("com.shxzhlxrr.reflect.vo.Person"); Constructor cons = cla.getDeclaredConstructor(String.class); cons.setAccessible(true); Object obj = cons.newInstance("张三"); //获取私有方法 Method sayMethod = cla.getDeclaredMethod("say", null); //设置权限 sayMethod.setAccessible(true); //调用 sayMethod.invoke(obj, null); } catch (Exception e) { e.printStackTrace(); } }
获取私有的属性
public void testPrivateField(){ try { //加载类 Class cla = Class.forName("com.shxzhlxrr.reflect.vo.Person"); Constructor cons = cla.getDeclaredConstructor(String.class); cons.setAccessible(true); Object obj = cons.newInstance("张三"); //获取name属性 Field nameField = cla.getDeclaredField("name"); //设置访问权限 nameField.setAccessible(true); //获得属性的值 String name = (String) nameField.get(obj); System.out.println("name:"+name); } catch (Exception e) { e.printStackTrace(); } }
当不确定类型的时候使用反射的例子
复制say
方法,重命名为say2
并该为共有的方法,测试使用。新建老师和学生类,继承人类这个类,并覆盖say2
。 我把学生和老师的类型存放到一个数组中,通过反射去调用了say2
方法。在我做过的以前的项目中,需要计算多个指标的 时候,我们可以把对应的计算类配置到数据库中,规定一个公共的方法,就可以调用这个方法进行各项指标的计算。
完整的代码如下所示:
package com.shxzhlxrr.reflect.vo; //学生类 public class Student extends Person{ @Override public void say2() { System.out.println("我的名字是:"+this.getName()+",我的职业是学生"); } }
package com.shxzhlxrr.reflect.vo; //老师类 public class Teacher extends Person{ @Override public void say2() { System.out.println("我的名字是:"+this.getName()+",我的职业是老师"); } }
public class ReflectTest2 { /** * 给定类的名字,调用指定的方法 * @param args */ public static void main(String[] args) { ReflectTest2 reflectTest2 = new ReflectTest2(); String[] classArray = new String[]{"com.shxzhlxrr.reflect.vo.Teacher","com.shxzhlxrr.reflect.vo.Student"}; for(String className : classArray){ try { reflectTest2.reflectMethod("say2", className); } catch (Exception e) { e.printStackTrace(); } } } public void reflectMethod(String methodName,String className) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{ Class cla = Class.forName(className); java.lang.reflect.Method method = cla.getDeclaredMethod(methodName, null);//正确的做法,参数也应是传进来的,不应该默认是null method.invoke(cla.newInstance(), null); } }