zoukankan      html  css  js  c++  java
  • java 反射

    反射:就是把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类,额外添加了birthday属性。

     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);
  • 相关阅读:
    内存映射文件原理探索(转)
    inux内存映射和共享内存理解和区别
    MySQL中的sleep函数介绍
    flask源码解析之上下文为什么用栈
    linux system函数详解
    Python中的可迭代对象、迭代器和生成器,协程的异同点
    GB2312汉字区位码、交换码和机内码转换方法 (ZT)
    pthread_cond_signal该放在什么地方?
    IPC介绍——10个ipcs例子
    lsof
  • 原文地址:https://www.cnblogs.com/zhangtianq/p/5879602.html
Copyright © 2011-2022 走看看