反射(Reflection)加载类,并解剖出类的各个组成部分(反射就是解剖的意思)

  • 加载类,获得类的字节码(三种方式):

  1. Class clazz1 = Class.forName("cn.xxx.bean.Person");

  2. Class clazz2 = new Person().getClass();

  3. Class clazz3 = Person().class;

  • 解剖出类中的各个组成部分:

获得公共构造方法、公共方法、和公共属性:

  1. public Constructor getConstructor(Class<?> ...ParameterTypes)

  2. public Method getMethod(String name, Class<?> ...parameterTypes)

  3. public Field getField(String name)  //或getFields获取所有属性

获得所有的构造方法、公共方法、和公共属性:

  1. public Constructor getDeclaredConstructor(Class<?>...ParameterTypes)

  2. public Method getDeclaredMethod(String name, Class<?>...parameterTypes)

  3. public Field getDeclaredField(String name)

反射一个类的构造方法,创建该类的对象:

  1. 反射无参数构造方法:Constructor c = clazz1.getConstructor(null); Person p = (Person) c.newInstance(null);

  2. 反射参数为String的构造方法:Constructor c = clazz1.getConstructor(String.class); Person p = (Person) c.newInstance("name");

  3. 反射参数为(String, int)的构造方法:Constructor c = clazz1.getConstructor(String.class, int.class); Person p = (Person) c.newInstance("name", 123);

  4. 反射参数为List的私有构造方法:Constructor c = clazz1.getDeclaredConstructor(List.class); c.setAccessible(true); Person p = (Person) c.newInstance(new ArrayList());

  5. 简化的方式(无参数的情况):Person p = (Person) clazz1.newInstance();  //要求Person类中有无参的构造方法

反射并调用一个类的方法:

  1. 反射一个无参数的方法 aa1(){}:Method m = clazz1.getMethod("aa1", null); m.invoke(pnull); //p为前面创建的对象

  2. 反射带参数的方法 aa1(String, int){}:Method m = clazz1.getMethod("aa1", String.class, int.class); m.invoke(p, "张三", 38);

  3. 反射带参数的方法 aa1(String, int[]){}:Method m = clazz1.getMethod("aa1", String.class, int[].class); m.invoke(p, "张三", new int[]{38, 39});

  4. 反射带参数的私有方法 aa1(InputString){}:Method m = clazz1.getDeclaredMethod("aa1", InputString.class); m.setAccessible(true); m.invoke(p, new FileInputStream("c:\\1.txt"));

  5. 反射带参数的静态方法 aa1(int){}:Method m = clazz1.getMethod("aa1", int.class); m.invoke(p, 23); //p可以用null代替

  6. 反射main(String[])方法:Method m = clazz1.getMethod("main", String[].class); m.invoke(null(Object)new String[]{"aa","bb"});  //注:一定要强转为一个Object,不然JDK为了向下兼容会把String[]先拆成两个参数再invoke,导致Wrong Number of Arguments错误

反射一个类中的属性:

  1. 获得一个属性的类型:Field f = clazz1.getField("name"); Class t = f.getType(); if(type.equals(String.class)){};

  2. 反射String name并获得它的值:Field f = clazz1.getField("name"); String name =(String) f.get(p); //p为前面创建的对象

  3. 反射String name并对它赋值:Field f = clazz1.getField("name"); String name =(String) f.set(p, "xxxxxx"); 

  4. 反射private int num:Field f = clazz1.getDeclaredField("num"); f.setAccessible(true); int num =(int) f.get(p); 

  5. 反射private static int age:Field f = clazz1.getDeclaredField("age"); f.setAccessible(true); int age=(int) f.get(p); 


内省(Introspector)用于方便地反射和操作Java Bean的属性

内省工具类:Introspector(java.beans.*包中

[java] view plain copy

  1. //获取Bean信息:  

  2. BeanInfo info = Introspector.getBeanInfo(Person.class);   

  3. //注:如果不想获取所继承的属性,则用getBeanInfo(Person.class, stopClass.class); stopClass是某一个祖先类,这个例子表示只获得stopClass的子孙直到Person的属性,不包括stopClass。  

  • 获得Bean的所有属性:

[java] view plain copy

  1. PropertyDescriptor[] pds = info.getPropertyDescriptors();  

  2.   

  3. for (PropertyDescriptor pd : pds){  

  4.     System.out.println(pd.getName());    //获得属性的名称。注:只要有getter就算是一个属性,不一定要真正定义属性。实际上是获取getter中去掉“get”后把第一个字母变小写的字符串。  

  5. }  


  • 获取Bean的一个属性:

[java] view plain copy

  1. PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); //获得age属性  

  2. Method setter = pd.getWriteMethod();    //获得setter  

  3. setter.invoke(p, 45);    //p为之前获得的一个Person实例  

  4. Method getter = pd.getReadMethod();    //获得getter  

  5. System.out.println(getter.invoke(p, null));   


获取一个属性的类型

[java] view plain copy

  1. System.out.println(pd.getPropertyType());  

  • 使用beanUtils(Apache开源项目)操纵java bean的属性:

需要使用第三方的包:commons-logging.jar, commons-beanutils-x.x.x.jar

[java] view plain copy

  1. //为属性name赋值:  

  2. BeanUtils.setProperty(p, "name""Jack");   //p为一个Person实例  

  3.   

  4. //自动类型转换:  

  5. BeanUtils.setProperty(p, "age""123");   //如果age属性是int,BeanUtils会自动把字符串“123”转换为int类型  

  6. //注:BeanUtils缺省只支持把String转成8种基本数据类型。  

  7.   

  8. //给BeanUtils注册类型转换器:  

  9. ConvertUtils.register(new Converter(){    //注册一个日期转换器:String转Date  

  10.         public Object convert(Class type, Object value){  

  11.             if(value==null){  

  12.                 return null;  

  13.             }  

  14.             if(!(value instanceof String)){    //如果不是String类型  

  15.                 throw new ConversionException("只支持String类型的转换");  

  16.             }  

  17.             String str = (String) value;  

  18.             if(str.trim().equals("")){  

  19.                 return null;  

  20.             }  

  21.   

  22.             SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");  

  23.             try {  

  24.                 return df.parse(str);    //字符串转Date  

  25.             }catch(ParseException e){  

  26.                 throw new RuntimeException(e); //e要传送给JVM  

  27.             }  

  28.         }  

  29.     }, Date.class);  

  30.   

  31. BeanUtils.setProperty(p, "birthDate""1980-01-02");    //  birthDate为Person中Date类型的属性  

注:BeanUtils jar包中已经定义好了一些实现了Converter接口的转换器,比如:

ConvertUtils.register(new DateLocaleConverter(), Date.class);

[java] view plain copy

  1. //把map填充到bean中:  

  2. Map map = new HashMap();  

  3. map.put("name""Jack");  

  4. map.put("birthdate""1908-01-02");  

  5. ...  

  6. ConvertUtils.register(new DateLocaleConverter(), Date.class);  

  7. Person p = new Persion();  

  8. BeanUtils.populate(p, map);    //map 填入 p 中  



转自Clement-Xu的csdn博客



  • 5