当前位置: 移动技术网 > IT编程>开发语言>Java > Java 内省(Introspector)深入理解

Java 内省(Introspector)深入理解

2019年07月22日  | 移动技术网IT编程  | 我要评论

warkey107,颍上天气,轮岗

java 内省(introspector)深入理解

一些概念:

  内省(introspector) 是java 语言对 javabean 类属性、事件的一种缺省处理方法。

  javabean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。如果在两个模块之间传递信息,可以将信息封装进javabean中,这种对象称为“值对象”(value object),或“vo”。方法比较少。这些信息储存在类的私有变量中,通过set()、get()获得。

  例如类userinfo :

package com.peidasoft.introspector;

public class userinfo {
  
  private long userid;
  private string username;
  private int age;
  private string emailaddress;
  
  public long getuserid() {
    return userid;
  }
  public void setuserid(long userid) {
    this.userid = userid;
  }
  public string getusername() {
    return username;
  }
  public void setusername(string username) {
    this.username = username;
  }
  public int getage() {
    return age;
  }
  public void setage(int age) {
    this.age = age;
  }
  public string getemailaddress() {
    return emailaddress;
  }
  public void setemailaddress(string emailaddress) {
    this.emailaddress = emailaddress;
  }
  
}

  在类userinfo中有属性 username, 那我们可以通过 getusername,setusername来得到其值或者设置新的值。通过 getusername/setusername来访问 username属性,这就是默认的规则。 java jdk中提供了一套 api 用来访问某个属性的 getter/setter 方法,这就是内省。

  jdk内省类库:

  propertydescriptor类:

  propertydescriptor类表示javabean类通过存储器导出一个属性。主要方法:

      1. getpropertytype(),获得属性的class对象;
      2. getreadmethod(),获得用于读取属性值的方法;getwritemethod(),获得用于写入属性值的方法;
      3. hashcode(),获取对象的哈希值;
      4. setreadmethod(method readmethod),设置用于读取属性值的方法;
      5. setwritemethod(method writemethod),设置用于写入属性值的方法。

  实例代码如下:

package com.peidasoft.introspector;

import java.beans.beaninfo;
import java.beans.introspector;
import java.beans.propertydescriptor;
import java.lang.reflect.method;

public class beaninfoutil { 
 
  public static void setproperty(userinfo userinfo,string username)throws exception{
    propertydescriptor propdesc=new propertydescriptor(username,userinfo.class);
    method methodsetusername=propdesc.getwritemethod();
    methodsetusername.invoke(userinfo, "wong");
    system.out.println("set username:"+userinfo.getusername());
  }
 
  public static void getproperty(userinfo userinfo,string username)throws exception{
    propertydescriptor prodescriptor =new propertydescriptor(username,userinfo.class);
    method methodgetusername=prodescriptor.getreadmethod();
    object objusername=methodgetusername.invoke(userinfo);
    system.out.println("get username:"+objusername.tostring());
  }
} 

  introspector类:

  将javabean中的属性封装起来进行操作。在程序把一个类当做javabean来看,就是调用introspector.getbeaninfo()方法,得到的beaninfo对象封装了把这个类当做javabean看的结果信息,即属性的信息。

  getpropertydescriptors(),获得属性的描述,可以采用遍历beaninfo的方法,来查找、设置类的属性。具体代码如下:

package com.peidasoft.introspector;

import java.beans.beaninfo;
import java.beans.introspector;
import java.beans.propertydescriptor;
import java.lang.reflect.method;


public class beaninfoutil {
    
  public static void setpropertybyintrospector(userinfo userinfo,string username)throws exception{
    beaninfo beaninfo=introspector.getbeaninfo(userinfo.class);
    propertydescriptor[] prodescrtptors=beaninfo.getpropertydescriptors();
    if(prodescrtptors!=null&&prodescrtptors.length>0){
      for(propertydescriptor propdesc:prodescrtptors){
        if(propdesc.getname().equals(username)){
          method methodsetusername=propdesc.getwritemethod();
          methodsetusername.invoke(userinfo, "alan");
          system.out.println("set username:"+userinfo.getusername());
          break;
        }
      }
    }
  }
  
  public static void getpropertybyintrospector(userinfo userinfo,string username)throws exception{
    beaninfo beaninfo=introspector.getbeaninfo(userinfo.class);
    propertydescriptor[] prodescrtptors=beaninfo.getpropertydescriptors();
    if(prodescrtptors!=null&&prodescrtptors.length>0){
      for(propertydescriptor propdesc:prodescrtptors){
        if(propdesc.getname().equals(username)){
          method methodgetusername=propdesc.getreadmethod();
          object objusername=methodgetusername.invoke(userinfo);
          system.out.println("get username:"+objusername.tostring());
          break;
        }
      }
    }
  }
  
}

    通过这两个类的比较可以看出,都是需要获得propertydescriptor,只是方式不一样:前者通过创建对象直接获得,后者需要遍历,所以使用propertydescriptor类更加方便。

  使用实例:

package com.peidasoft.introspector;

public class beaninfotest {

  /**
   * @param args
   */
  public static void main(string[] args) {
    userinfo userinfo=new userinfo();
    userinfo.setusername("peida");
    try {
      beaninfoutil.getproperty(userinfo, "username");
      
      beaninfoutil.setproperty(userinfo, "username");
      
      beaninfoutil.getproperty(userinfo, "username");
      
      beaninfoutil.setpropertybyintrospector(userinfo, "username");      
      
      beaninfoutil.getpropertybyintrospector(userinfo, "username");
      
      beaninfoutil.setproperty(userinfo, "age");
      
    } catch (exception e) {
      // todo auto-generated catch block
      e.printstacktrace();
    }

  }

}

  输出:

get username:peida
set username:wong
get username:wong
set username:alan
get username:alan
java.lang.illegalargumentexception: argument type mismatch
  at sun.reflect.nativemethodaccessorimpl.invoke0(native method)
  at sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39)
  at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:25)
  at java.lang.reflect.method.invoke(method.java:597)
  at com.peidasoft.introspector.beaninfoutil.setproperty(beaninfoutil.java:14)
  at com.peidasoft.introspector.beaninfotest.main(beaninfotest.java:22) 

  说明:beaninfoutil.setproperty(userinfo, "age");报错是应为age属性是int数据类型,而setproperty方法里面默认给age属性赋的值是string类型。所以会爆出argument type mismatch参数类型不匹配的错误信息。

  beanutils工具包:

  由上述可看出,内省操作非常的繁琐,所以所以apache开发了一套简单、易用的api来操作bean的属性——beanutils工具包。

  beanutils工具包:下载:http://commons.apache.org/beanutils/ 注意:应用的时候还需要一个logging包 http://commons.apache.org/logging/

  使用beanutils工具包完成上面的测试代码:

package com.peidasoft.beanutil;

import java.lang.reflect.invocationtargetexception;

import org.apache.commons.beanutils.beanutils;
import org.apache.commons.beanutils.propertyutils;

import com.peidasoft.introspector.userinfo;

public class beanutiltest {
  public static void main(string[] args) {
    userinfo userinfo=new userinfo();
     try {
      beanutils.setproperty(userinfo, "username", "peida");
      
      system.out.println("set username:"+userinfo.getusername());
      
      system.out.println("get username:"+beanutils.getproperty(userinfo, "username"));
      
      beanutils.setproperty(userinfo, "age", 18);
      system.out.println("set age:"+userinfo.getage());
      
      system.out.println("get age:"+beanutils.getproperty(userinfo, "age"));
       
      system.out.println("get username type:"+beanutils.getproperty(userinfo, "username").getclass().getname());
      system.out.println("get age type:"+beanutils.getproperty(userinfo, "age").getclass().getname());
      
      propertyutils.setproperty(userinfo, "age", 8);
      system.out.println(propertyutils.getproperty(userinfo, "age"));
      
      system.out.println(propertyutils.getproperty(userinfo, "age").getclass().getname());
         
      propertyutils.setproperty(userinfo, "age", "8");  
    } 
     catch (illegalaccessexception e) {
      e.printstacktrace();
    } 
     catch (invocationtargetexception e) {
      e.printstacktrace();
    }
    catch (nosuchmethodexception e) {
      e.printstacktrace();
    }
  }
}

  运行结果:

set username:peida
get username:peida
set age:18
get age:18
get username type:java.lang.string
get age type:java.lang.string
8
java.lang.integer
exception in thread "main" java.lang.illegalargumentexception: cannot invoke com.peidasoft.introspector.userinfo.setage 
on bean class 'class com.peidasoft.introspector.userinfo' - argument type mismatch - had objects of type "java.lang.string" 
but expected signature "int"
  at org.apache.commons.beanutils.propertyutilsbean.invokemethod(propertyutilsbean.java:2235)
  at org.apache.commons.beanutils.propertyutilsbean.setsimpleproperty(propertyutilsbean.java:2151)
  at org.apache.commons.beanutils.propertyutilsbean.setnestedproperty(propertyutilsbean.java:1957)
  at org.apache.commons.beanutils.propertyutilsbean.setproperty(propertyutilsbean.java:2064)
  at org.apache.commons.beanutils.propertyutils.setproperty(propertyutils.java:858)
  at com.peidasoft.orm.beanutil.beanutiltest.main(beanutiltest.java:38)
caused by: java.lang.illegalargumentexception: argument type mismatch
  at sun.reflect.nativemethodaccessorimpl.invoke0(native method)
  at sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:39)
  at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:25)
  at java.lang.reflect.method.invoke(method.java:597)
  at org.apache.commons.beanutils.propertyutilsbean.invokemethod(propertyutilsbean.java:2170)
  ... 5 more

  说明:

  1.获得属性的值,例如,beanutils.getproperty(userinfo,"username"),返回字符串

  2.设置属性的值,例如,beanutils.setproperty(userinfo,"age",8),参数是字符串或基本类型自动包装。设置属性的值是字符串,获得的值也是字符串,不是基本类型。   3.beanutils的特点:
    1). 对基本数据类型的属性的操作:在web开发、使用中,录入和显示时,值会被转换成字符串,但底层运算用的是基本类型,这些类型转到动作由beanutils自动完成。
    2). 对引用数据类型的属性的操作:首先在类中必须有对象,不能是null,例如,private date birthday=new date();。操作的是对象的属性而不是整个对象,例如,beanutils.setproperty(userinfo,"birthday.time",111111);   

package com.peidasoft.introspector;
import java.util.date;

public class userinfo {

  private date birthday = new date();
  
  public void setbirthday(date birthday) {
    this.birthday = birthday;
  }
  public date getbirthday() {
    return birthday;
  }   
}

package com.peidasoft.beanutil;

import java.lang.reflect.invocationtargetexception;
import org.apache.commons.beanutils.beanutils;
import com.peidasoft.introspector.userinfo;

public class beanutiltest {
  public static void main(string[] args) {
    userinfo userinfo=new userinfo();
     try {
      beanutils.setproperty(userinfo, "birthday.time","111111"); 
      object obj = beanutils.getproperty(userinfo, "birthday.time"); 
      system.out.println(obj);     
    } 
     catch (illegalaccessexception e) {
      e.printstacktrace();
    } 
     catch (invocationtargetexception e) {
      e.printstacktrace();
    }
    catch (nosuchmethodexception e) {
      e.printstacktrace();
    }
  }
}

  3.propertyutils类和beanutils不同在于,运行getproperty、setproperty操作时,没有类型转换,使用属性的原有类型或者包装类。由于age属性的数据类型是int,所以方法propertyutils.setproperty(userinfo, "age", "8")会爆出数据类型不匹配,无法将值赋给属性。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网