反射(Reflection):加载类,并解剖出类的各个组成部分(反射就是解剖的意思)
- 加载类,获得类的字节码(三种方式):
- Class clazz1 = Class.forName("cn.xxx.bean.Person");
- Class clazz2 = new Person().getClass();
- Class clazz3 = Person().class;
- 解剖出类中的各个组成部分:
获得公共构造方法、公共方法、和公共属性:
- public Constructor getConstructor(Class<?> ...ParameterTypes)
- public Method getMethod(String name, Class<?> ...parameterTypes)
- public Field getField(String name) //或getFields获取所有属性
获得所有的构造方法、公共方法、和公共属性:
- public Constructor getDeclaredConstructor(Class<?>...ParameterTypes)
- public Method getDeclaredMethod(String name, Class<?>...parameterTypes)
- public Field getDeclaredField(String name)
反射一个类的构造方法,创建该类的对象:
- 反射无参数构造方法:Constructor c = clazz1.getConstructor(null); Person p = (Person) c.newInstance(null);
- 反射参数为String的构造方法:Constructor c = clazz1.getConstructor(String.class); Person p = (Person) c.newInstance("name");
- 反射参数为(String, int)的构造方法:Constructor c = clazz1.getConstructor(String.class, int.class); Person p = (Person) c.newInstance("name", 123);
- 反射参数为List的私有构造方法:Constructor c = clazz1.getDeclaredConstructor(List.class); c.setAccessible(true); Person p = (Person) c.newInstance(new ArrayList());
- 简化的方式(无参数的情况):Person p = (Person) clazz1.newInstance(); //要求Person类中有无参的构造方法
反射并调用一个类的方法:
- 反射一个无参数的方法 aa1(){}:Method m = clazz1.getMethod("aa1", null); m.invoke(p, null); //p为前面创建的对象
- 反射带参数的方法 aa1(String, int){}:Method m = clazz1.getMethod("aa1", String.class, int.class); m.invoke(p, "张三", 38);
- 反射带参数的方法 aa1(String, int[]){}:Method m = clazz1.getMethod("aa1", String.class, int[].class); m.invoke(p, "张三", new int[]{38, 39});
- 反射带参数的私有方法 aa1(InputString){}:Method m = clazz1.getDeclaredMethod("aa1", InputString.class); m.setAccessible(true); m.invoke(p, new FileInputStream("c:\\1.txt"));
- 反射带参数的静态方法 aa1(int){}:Method m = clazz1.getMethod("aa1", int.class); m.invoke(p, 23); //p可以用null代替
- 反射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错误
反射一个类中的属性:
- 获得一个属性的类型:Field f = clazz1.getField("name"); Class t = f.getType(); if(type.equals(String.class)){};
- 反射String name并获得它的值:Field f = clazz1.getField("name"); String name =(String) f.get(p); //p为前面创建的对象
- 反射String name并对它赋值:Field f = clazz1.getField("name"); String name =(String) f.set(p, "xxxxxx");
- 反射private int num:Field f = clazz1.getDeclaredField("num"); f.setAccessible(true); int num =(int) f.get(p);
- 反射private static int age:Field f = clazz1.getDeclaredField("age"); f.setAccessible(true); int age=(int) f.get(p);
内省(Introspector):用于方便地反射和操作Java Bean的属性
内省工具类:Introspector(
java.beans.*包中)
- //获取Bean信息:
- BeanInfo info = Introspector.getBeanInfo(Person.class);
- //注:如果不想获取所继承的属性,则用getBeanInfo(Person.class, stopClass.class); stopClass是某一个祖先类,这个例子表示只获得stopClass的子孙直到Person的属性,不包括stopClass。
- 获得Bean的所有属性:
- PropertyDescriptor[] pds = info.getPropertyDescriptors();
- for (PropertyDescriptor pd : pds){
- System.out.println(pd.getName()); //获得属性的名称。注:只要有getter就算是一个属性,不一定要真正定义属性。实际上是获取getter中去掉“get”后把第一个字母变小写的字符串。
- }
- 获取Bean的一个属性:
- PropertyDescriptor pd = new PropertyDescriptor("age", Person.class); //获得age属性
- Method setter = pd.getWriteMethod(); //获得setter
- setter.invoke(p, 45); //p为之前获得的一个Person实例
- Method getter = pd.getReadMethod(); //获得getter
- System.out.println(getter.invoke(p, null));
获取一个属性的类型
- System.out.println(pd.getPropertyType());
- 使用beanUtils(Apache开源项目)操纵java bean的属性:
需要使用第三方的包:commons-logging.jar, commons-beanutils-x.x.x.jar
- //为属性name赋值:
- BeanUtils.setProperty(p, "name", "Jack"); //p为一个Person实例
- //自动类型转换:
- BeanUtils.setProperty(p, "age", "123"); //如果age属性是int,BeanUtils会自动把字符串“123”转换为int类型
- //注:BeanUtils缺省只支持把String转成8种基本数据类型。
- //给BeanUtils注册类型转换器:
- ConvertUtils.register(new Converter(){ //注册一个日期转换器:String转Date
- public Object convert(Class type, Object value){
- if(value==null){
- return null;
- }
- if(!(value instanceof String)){ //如果不是String类型
- throw new ConversionException("只支持String类型的转换");
- }
- String str = (String) value;
- if(str.trim().equals("")){
- return null;
- }
- SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
- try {
- return df.parse(str); //字符串转Date
- }catch(ParseException e){
- throw new RuntimeException(e); //e要传送给JVM
- }
- }
- }, Date.class);
- BeanUtils.setProperty(p, "birthDate", "1980-01-02"); // birthDate为Person中Date类型的属性
注:BeanUtils jar包中已经定义好了一些实现了Converter接口的转换器,比如:
ConvertUtils.register(
new DateLocaleConverter(), Date.
class);
- //把map填充到bean中:
- Map map = new HashMap();
- map.put("name", "Jack");
- map.put("birthdate", "1908-01-02");
- ...
- ConvertUtils.register(new DateLocaleConverter(), Date.class);
- Person p = new Persion();
-
- BeanUtils.populate(p, map); //map 填入 p 中
注:转自Clement-Xu