码迷,mamicode.com
首页 > 编程语言 > 详细

java 反射

时间:2016-09-17 23:57:17      阅读:408      评论:0      收藏:0      [点我收藏+]

标签:

 

反射:就是把Java类中的各种成分映射成一个个的Java对象。例如,一个类有:成员变量,成员方法,包等信息,利用反射技术可以对一个类进行解剖,把各个部分映射成一个个对象。

 


 

1. 先得到类的字节码对象:Class cl = Class.forName("类的全名");

                            或者:Class cl = 类名.class;

                            或者:Class cl = 类的对象.getClass();

2. 解剖类:

   Class对象提供了如下常用方法:

  •    public Constructor getConstructor(Class<?>...parameterTypes)
  •    public Method getMethod(String name, Class<?>...parameterTypes)
  •    public Field getField(String name)
  •    public Constructor getDeclaredConstructor(Class<?>...parameterTypes)
  •    public Method getDeclaredMethod(String name, Class<?>...parameterTypes)
  •    public Field getDeclaredField(String name)

 这些方法分别用于从类中解剖出构造函数、方法和成员变量(属性)。解剖出的成员分别使用Constructor、Method、Field对象表示。

先写一个简单的类

 1 package javatext;
 2 
 3 import java.util.Date;
 4 
 5 public class Student {
 6     public String str = "hello";
 7 
 8     private int age = 18;
 9 
10     public static Date time;
11     
12     public Student(){}
13 
14     public Student(String name){
15         System.out.println("姓名:" + name);
16     }
17 
18     public Student(String name, int age){
19         System.out.println(name + " " + age);
20     }
21 
22     private Student(int age){
23         System.out.println("年龄:" + age);
24     }
25 
26     public void m1(){
27         System.out.println("m1");
28     }
29 
30     public void m2(String name){
31         System.out.println("m2 " + name);
32     }
33 
34     public String m3(String name, int age){
35         System.out.println("m3 " + name + " " + age);
36         return "m3:OK";
37     }
38 
39     private void m4(int age){
40         System.out.println("m4 " + age);
41     }
42 
43     public static void m5(){
44         System.out.println("m5");
45     }
46 
47     private static void m6(String[] str){
48         System.out.println(str.length);
49     }
50 }

 

反射

 1 package javatext;
 2 
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.Field;
 5 import java.lang.reflect.Method;
 6 import java.util.Date;
 7 
 8 public class _1{
 9     
10     public static void main(String[] args)throws Exception{
11         Class cl = Class.forName("javatext.Student"); //Student类在内存中的字节码对象
12         
13         Student s = (Student)cl.newInstance();  //可以直接用类的字节码对象,建立该类新的实例,调用的是默认的构造方法
14         System.out.println(s.str);
15         
16         Constructor c = cl.getConstructor(String.class);  //获取相应的构造方法,只能是public的方法
17         c.newInstance("Chris"); //创建新实例
18         
19         Constructor cc = cl.getDeclaredConstructor(int.class); //获取相应的构造方法(所有,包括私有构造方法)
20         cc.setAccessible(true);
21         cc.newInstance(22);
22         
23         Constructor[] ccc = cl.getDeclaredConstructors();  //获取所有的构造方法(包括私有)
24         System.out.println(ccc.length);
25         
26         Method m1 = cl.getMethod("m1", null); //获取名为m1,参数为null的方法
27         m1.invoke(s, null);  //调用该方法,s为该类的一个实例,null为该方法的参数
28         
29         Method m2 = cl.getMethod("m2", String.class);
30         m2.invoke(s, "Chris");
31         
32         Method m3 = cl.getMethod("m3", String.class, int.class);
33         String str = (String)m3.invoke(s, "Chris", 22);
34         System.out.println(str);
35         
36         Method m4 = cl.getDeclaredMethod("m4", int.class);
37         m4.setAccessible(true);
38         m4.invoke(s, 22);
39         
40         Method m5 = cl.getMethod("m5", null);
41         m5.invoke(null, null);  //对于静态方法,对象可以为s,也可以为null
42         
43         Method m6 = cl.getDeclaredMethod("m6", String[].class);
44         m6.setAccessible(true);
45         m6.invoke(null, (Object)new String[]{"a", "b", "c"}); //参数中带有数组的,要将其转换成一个对象
46         //注:由于要向下兼容,jdk1.5及以上版本要兼容jdk1.4。在1.4中,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给
47         //invoke方法时,会出现参数数量错误的问题。
48         //解决办法:invoke(null, new Object[]{new String[]{"xxx", "xx"}});
49         //  或者:  invoke(null, (Object)new String[]{"XX", "XXX"});
50         //这样编译器会做特殊处理,编译时不把参数当作数组看待,也就不会将数组打散成若干参数了。
51         
52         Field f1 = cl.getField("str");
53         String string = (String)f1.get(s);
54         System.out.println(string);
55         
56         f1.set(s, "hehe"); //更改类中的str字段
57         System.out.println(s.str);
58         
59         Field f2 = cl.getDeclaredField("age");
60         f2.setAccessible(true);
61         int age = (Integer)f2.get(s);
62         System.out.println(age);
63         
64         f2.set(s, 80);
65         age = (Integer)f2.get(s);
66         System.out.println(age);
67         
68         Field f3 = cl.getField("time");
69         f3.set(null, new Date());
70         System.out.println(Student.time);
71     }    
72 } 

 结果:

hello
姓名:Chris
年龄:22
4
m1
m2 Chris
m3 Chris 22
m3:OK
m4 22
m5
3
hello
hehe
18
80
Sat Sep 17 20:38:34 GMT+08:00 2016

 


 

内省:开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以Sun公司开发了一套API,专门用于操作java对象的属性。

通过内省技术访问(java.beans包提供了内省的API)JavaBean的两种方式。

1. 通过Introspector类获得Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。

2. 通过PropertyDescriptor类操作Bean的属性。

写一个简单类:

 1 package javatext;
 2 
 3 public class Person {
 4     private String name = "Chris";
 5     private int age;
 6     public String getName() {
 7         return name;
 8     }
 9     public void setName(String name) {
10         this.name = name;
11     }
12     public int getAge() {
13         return age;
14     }
15     public void setAge(int age) {
16         this.age = age;
17     }
18 }

内省:

package javatext;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public class _1{
    public static void main(String[] args)throws Exception{
        Person p = new Person();
        
        //获取所有属性
        BeanInfo bi = Introspector.getBeanInfo(Person.class);//获取Person类中的属性,被封装到了BeanInfo中,若想获得(不包括Object类中的)属性,则参数为(Person.class, Object.class)
        PropertyDescriptor[] pds = bi.getPropertyDescriptors();//获取类中的所有的属性描述器
        System.out.println(pds.length); //显示3个属性,以为Object类中有getClass()方法,也算作1个属性
        for(PropertyDescriptor pd : pds){
            System.out.println(pd.getName()); //打印属性名称,即去掉get、set的名称
        }
        
        //操作Bean的指定属性
        PropertyDescriptor pd = new PropertyDescriptor("name", Person.class);
        Method m = pd.getReadMethod(); //获取getName()方法,即读方法
        String value = (String)m.invoke(p, null);
        System.out.println(value);
        
        Method m1 = pd.getWriteMethod(); //获取setName()方法,即写方法
        m1.invoke(p, "Lily");
        System.out.println(p.getName());
    }    
} 

 结果:

3
age
class
name
Chris
Lily

 

内省--beanutils工具包:

Beanutils是Apache开发的一套快速操作JavaBean getter/setter方法的API,目前比较流行。

准备包:commons-beanutils.jar, commons-logging.jar

语法:

 (1)设置:BeanUtils.setProperty(Object bean, String propertyName, String propertyValue);

 (2)获取:BeanUtils.getProperty(Object bean, String PropertyName);

注:BeanUtils可以进行类型的自动转换,但仅限基本类型。

继续用上面的Person类

 1 package javatext;
 2 
 3 import java.text.DateFormat;
 4 import java.text.SimpleDateFormat;
 5 import java.util.Date;
 6 
 7 import org.apache.commons.beanutils.BeanUtils;
 8 import org.apache.commons.beanutils.ConvertUtils;
 9 import org.apache.commons.beanutils.Converter;
10 import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
11 
12 public class _1{
13     public static void main(String[] args)throws Exception{
14         Person p = new Person();
15         String str = BeanUtils.getProperty(p, "name"); //调用getName()方法
16         System.out.println(str);
17         
18         BeanUtils.setProperty(p, "name", "Lily"); //设置值
19         System.out.println(p.getName());
20         
21         //非基本类型的属性设置
22         //给BeanUtils注册类型转换器
23         ConvertUtils.register(new Converter(){
24             //type:目标类型
25             //value:当前传入的值
26             public Object convert(Class type, Object value){
27 //                if(type.equals(Date.class)){
28 //                    //字符串转换为Date
29 //                }else{
30 //                    //Date转换为字符串
31 //                }
32                 DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
33                 if(value instanceof String){
34                     //字符串转换为Date
35                     String v = (String)value;
36                     try{
37                         Date d = df.parse(v);
38                         return d;
39                     }catch(Exception e){
40                         throw new RuntimeException(e);
41                     }
42                 }else{
43                     //Date转换为字符串
44                     Date d = (Date)value;
45                     return df.format(d);
46                 }
47             }
48         }, Date.class);
49         BeanUtils.setProperty(p, "birthday", "2016-09-17");
50         System.out.println(p.getBirthday());

 

结果:

Chris
Lily
Sat Sep 17 00:00:00 GMT+08:00 2016

 

或者

1 ConvertUtils.register(new DateLocaleConverter(), Date.class);
2 BeanUtils.setProperty(p, "birthday", "1999-09-09");
3 System.out.println(p.getBirthday());

注:其中的DateLocalConverter()就是对上面代码的封装。

 

BeanUtils将Map属性自动放到Bean中

注:可以操作的原则是,Map的key必须要与Bean的属性一致。

 

1 Map m = new HashMap();
2 m.put("name", "Chris");
3 Person p = new Person();
4 BeanUtils.populate(p, m);
5 System.out.println(person);

 

java 反射

标签:

原文地址:http://www.cnblogs.com/zhangtianq/p/5879602.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!