本文按照以下思路帮助自己和路人理清反射。
1.什么是反射?
2.反射能干什么?
3.怎么用?
4.案例实操:
5.总结:
一、什么是反射?
百度百科:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及
动态调用对象方法的功能称为java语言的反射机制。
说的通俗一点,反射是在程序编译完成后,在.class运行阶段起作用的,你给我传过来什么,我都能访问它祖宗十八代,从而达到我的目的。重点在于动态,动态指的是运行阶段,而非编译阶段。
二、反射能干什么?
常见的有加载数据库驱动中Class.forName(driverClass),还有许多框架例如spring也大量的使用反射,还有自己的项目中抽取dao层公共方法写到BaseDaoImpl中需要知道传递的实体类型等等,都可以通过反射来获取。
三、怎么用?
三种方式可以选择,总之是要获取Class类对象
3.1.通过对象(不常用,对象都有了还反过用对象再反射属性方法,多此一举)
Person p = new Person();
Class<? extends Person> clazz = p.getClass();
3.2.通过类名(不常用,没有必要)
Class<? extends Person> clazz = Person.class();
3.3.通过字符串全类名(常用,一般情况下,我们没法传递过去一个类对象,但是我们可以通过该类的全限定名,间接得到类的信息)
Class<?> clazz = Class.forName("com.xx.myReflect");
四、案例实操
前面都很简单,下面就使用第三种方式,具体测试反射在字段,普通方法,构造方法上的一些使用,其余的类似,自己探索,被测试的类如下。
4.1 测试字段
@Test public void testField(){ try { //通过反射在运行期间加载MyReflect类的.class文件,得到Class对象,Class对象的详细描述了呗代理类 Class<?> clazz = Class.forName("com.cissst.vo.MyReflect"); //因为要给字段中设值,因此产生Reflect的实例,父类是Object Object object = clazz.newInstance(); //得到本类(不包含父类)中的声明字段数组 Field[] fields = clazz.getDeclaredFields(); //循环设置字段值,输出字段值 for(Field f : fields){ //因为某些字段或者方法是私有的,反射需要将此标识设置为true f.setAccessible(true); //判断如果当前字段类型是否是Integer //如果使用getName,获取的是全限定名 if(f.getType().getSimpleName().equals("Integer")){ //是设置为1 f.set(object, 1); } //判断如果当前字段类型是否是String if(f.getType().getSimpleName().equals("String")){ //是设置为.. f.set(object, "秦琼"); } //最后输出,腰肢具体详情请查看API System.out.println(f.get(object)); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }
4.2 测试方法
/* * 测试普通方法 */ @Test public void testMethod(){ try { //通过反射在运行期间加载MyReflect类的.class文件,得到Class对象,Class对象的详细描述了呗代理类 Class<?> clazz = Class.forName("com.cissst.vo.MyReflect"); //产生Reflect的实例,父类是Object Object object = clazz.newInstance(); //指定方法名,指定参数类型,得到该方法,还有方法查API,很好用 Method method = clazz.getMethod("method", String.class); //执行此方法 method.invoke(object, "李逵"); } catch (Exception e) { e.printStackTrace(); } }
4.3 测试构造方法
/* * 测试构造方法 * */ @Test public void testConstractorMethod(){ try { //通过反射在运行期间加载MyReflect类的.class文件,得到Class对象,Class对象的详细描述了呗代理类 Class<?> clazz = Class.forName("com.cissst.vo.MyReflect"); //调用无参构造 Constructor<?> constructor = clazz.getDeclaredConstructor(); //通过无参构造实例化得到类对象 Object obj1 = constructor.newInstance(); //看得到的ojb和MyReflect是否是同一宗亲 System.out.println(obj1 instanceof MyReflect); //得到所有的构造 Constructor<?>[] constructors = clazz.getDeclaredConstructors(); //循环操作构造 for(Constructor<?> con : constructors){ //这里做个简单的判断,实际可能比这更复杂 if(con.getParameterCount()==0){ //无参构造实例化 Object ojb2 = con.newInstance(); //有参构造 }else if(con.getParameterCount()==2){ //有参构造实例化 Object ojb3 = con.newInstance(1,"林彪"); } } } catch (Exception e) { e.printStackTrace(); } }
被测试类:
package com.cissst.vo; /** * 普通类:用此类测试反射 * @author phoebe */ public class MyReflect{ //字段 private Integer id; private String name; /* * 无参构造方法 */ public MyReflect(){ System.out.println("无参构造is running"); } /* * 有参构造方法 */ public MyReflect(Integer id,String name){ this.id = id; this.name = name; System.out.println("有参构造"); } /* * 无参普通方法 */ public void method(){ System.out.println("无参普通方法"); } /* * 无参普通方法 */ public void method(String str){ System.out.println("有参普通方法"); } }
五、总结
反射使得代码更灵活,可以提高复用性。