JavaBean与内省操作

一.JavaBean

1.     什么叫做JavaBean?

JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

2.     JavaBean如此特殊,特殊之处在哪里?

A.     如果读取或设置某个类对象上的私有字段的值,则需要通过一些相应的方法来访问,通常会想到使用getter和setter方法来操作。例如有个方法叫做getName(),那么我们就可以知道,通过方法名字我们知道,这个方法使用来获取name属性的值的,所以name是一个私有的字段(属性);同理setName()当然是用来设置name属性的值的,依然反馈出name是一个私有的属性,显然这中方法的命名是很健壮的,所以JavaBean中的方法都是具有特定的命名规则,这样一个类中有这样的命名方法的方法,就可以当作JavaBean来使用。

B.     除此之外,我们知道具有JavaBean特点的类,除了方法有一些特殊的命名规则外,其实和普通类一样,所以我们也可以将其当作普通的类来使用。

C.     总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到Java类内部的成员变量。

3.     JavaBean方法命名规则细节说明

A.      一个JavaBean类中的方法,去掉set或get前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。

getAge/setAge-->age

gettime-->time

setTime-->time

B.      如果去掉前缀,剩余部分的第二个字母为大写,则全部大写

getCPU-->CPU。

4.     JavaBean作用

A.    如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO),这些信息在类中用私有字段来存储。

B.     在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作。

C.     JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。

二.内省操作

1.     什么叫做内省?

英文Introspector,名为内窥镜,内部检查,内省主要使用来对JavaBean进行操作的,所以当一个类满足了JavaBean的条件,就可以使用内省的方式来获取和操作JavaBean中的字段值。内省提供了操作JavaBean的API。

2.      JavaBean复杂内省操作

Java 中提供了一套 API 用来访问某个属性的getter/setter 方法,通过这些 API 可以使你不需要了解这个规则,这些 API 存放于包 java.beans 中,一般的做法是通过类Introspector 的getBeanInfo方法 来获取某个对象的BeanInfo 信息,然后通过BeanInfo 来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter 方法,然后我们就可以通过反射机制来调用这些方法。

A.     Introspector类

Introspector这个类位于Java.beans包中,该类中的方法都是静态的,可以直接使用类名调用。

static BeanInfo getBeanInfo(Class<?>beanClass) 在 JavaBean 上进行内省,了解其所有属性、公开的方法和事件。

我们可以使用Introspector的getBeanInfo(Class<?> beanClass)来获取一个JavaBean类的BeanInfo对象,然后通过BeanInfo对象的getPropertyDescriptors()方法获取属性描述器PropertyDescriptor对象的数组,通过遍历数组,可以获取到每个字段相对应的属性描述,通过描述器去获取设置和获取字段值的方法。

import java.beans.BeanDescriptor;  
import java.beans.BeanInfo;  
import java.beans.Introspector;  
import java.beans.PropertyDescriptor;  
import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
public class JavaBeanDemo1  
{  
    public static void main(String[] args) throws Exception  
    {  
          NoteBook myNoteBook = new NoteBook("Lenovo G470", 4800);  
//通过Introspector的getBeanInfo方法获取BeanInfo对象  
         BeanInfo info = Introspector.getBeanInfo(myNoteBook.getClass());  
//通过BeanInfo对象获取属性描述器对象数组  
          PropertyDescriptor[] pds = info.getPropertyDescriptors();  
          setProperty(myNoteBook, pds);  
          getProperty(myNoteBook, pds);  
    }  
  
public static void getProperty(NoteBook myNoteBook, PropertyDescriptor[] pds)  
throws Exception  
    {  
//通过遍历PropertyDescriptor[]数组,获取属性的获取值方法,并获取值。  
        for(PropertyDescriptor pd : pds )  
          {  
//打印属性的Class类型  
                System.out.println(pd.getPropertyType());  
//打印声明这个属性的类Class  
System.out.println( pd.getReadMethod().getDeclaringClass());  
              if("name".equals(pd.getName()))  
              {  
//获取这个属性值读取方法,并执行打印  
                  Method nameGet = pd.getReadMethod();  
                  System.out.println(nameGet.invoke(myNoteBook));  
              }  
              if("price".equals(pd.getName()))  
              {  
                  Method priceGet = pd.getReadMethod();  
                  System.out.println(priceGet.invoke(myNoteBook));  
              }  
          }  
    }  
  
public static void setProperty(NoteBook myNoteBook, PropertyDescriptor[] pds)  
            throws Exception  
    {  
//通过遍历PropertyDescriptor[]数组,获取属性的获取值方法,并获取值。     
        for(PropertyDescriptor pd : pds)  
          {  
                if("name".equals(pd.getName()))  
                {  
//设置这个属性值读取方法  
                        Method nameSet = pd.getWriteMethod();  
                        nameSet.invoke(myNoteBook,"Asus" );  
                }  
                if("price".equals(pd.getName()))  
                {  
                    Method priceSet = pd.getWriteMethod();  
                    priceSet.invoke(myNoteBook, 6000);  
                }  
          }  
    }  
  
}  
  
class NoteBook  
{  
     private String name ;  
     private int price;  
     public NoteBook(String name , int price)  
     {  
         this.name = name ;  
         this.price = price;  
     }  
     public void setName(String name )  
     {  
         this.name = name;  
     }  
     public String getName()  
     {  
         return this.name;  
     }  
     public void setPrice(int price)  
     {  
         this.price = price;  
     }  
     public int getPrice()  
     {  
         return this.price;  
     }  
     public String getX()  
     {  
         return "";  
     }  
}  

B.    PropertyDescriptor类

这个类位于java.beans包中,该类提供了三个构造方法,如下:

PropertyDescriptor(String propertyName, Class<?> beanClass) 通过调用 getFoo 和 setFoo存储器方法,为符合标准 Java约定的属性构造一个 PropertyDescriptor。

PropertyDescriptor(String propertyName, Class<?> beanClass, String readMethodName, String writeMethodName) 此构造方法带有一个简单属性的名称和用于读写属性的方法名称。

PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)

此构造方法带有某一简单属性的名称,以及用来读取和写入属性的 Method 对象。

通常我们只是用第一个构造方法,方便使用。

实例1:

<span style="font-size:14px">import java.beans.PropertyDescriptor;  
public class PropertyDescriptorDemo  
{  
    public static void main(String[] args)throws Exception  
    {  
        Person p = new Person("Kandy",25);  
        PropertyDescriptor pd = new PropertyDescriptor("name",p.getClass());  
      System.out.println(  pd.getName());//打印属性名  
      System.out.println(pd.getDisplayName());//打印属性名  
     System.out.println( pd.getPropertyType());//获取属性类型  
    }  
}</span>  

执行结果:

name

name

class java.lang.String

示例2:

<span style="font-size:14px">importjava.beans.PropertyDescriptor;  
importjava.lang.reflect.Method;  
public class PropertyDescriptorDemo  
{  
       public static voidmain(String[] args)throwsException  
       {  
              Person p = newPerson("Kandy",25);  
              //构建一个name属性的属性描述器  
              PropertyDescriptor pd = newPropertyDescriptor("name",p.getClass());  
              //通过属性描述器获取属性值设置方法  
       Method methodWrite = pd.getWriteMethod();  
        methodWrite.invoke(p,"Ansen");  
      //通过属性描述器获取属性值获取方法  
        Method methodRead = pd.getReadMethod();  
       Object value = methodRead.invoke(p);  
       System.out.println(value);  
       }  
}</span>  

执行结果为:Ansen

3.     开源扩展BeanUtils工具包

BeanUtils等工具包都是由阿帕奇提供的,为了便于开发。BeanUtils可以将8种基本数据类型进行自动的转换,也就是一字符串形式给,以字符串形式体现出来,因此对于非基本数据类型,就需要注册转换器Converter,这就需要ConverUtils包。

好处:

A.     提供的set或get方法中,传入的是字符串,返回的还是字符串,因为在浏览器中,用户输入到文本框的都是以字符串的形式发送至服务器上的,所以操作的都是字符串。也就是说这个工具包的内部有自动将整数转换为字符串的操作。

B.     支持属性的级联操作,即支持属性链。如可以设置:人的脑袋上的眼睛的眼珠的颜色。这种级联属性的属性连如果自己用反射,那就很困难了,通过这个工具包就可以轻松调用。

注意:

要使用BeanUtils,就要将BeanUtils包添加到build path中,注意如果要正常使用,还要将还要将Apache公司的logging(日志)的jar包也添加进BuildPath。

在工程中导入工具jar包

两种方式:

A.     右键项目--选择Properties---Java Build Path--选择Liberiers标签。AddExternal Jars--选择要导入的jar包。即可。这样做有个问题就是如果jar路径发生变化。项目就不能使用到这个jar包。

B.     在项目中建立一个lib目录,专门用于存放项目所使用到的jar工具包。将要使用到jar包复制粘贴进来,并在jar上点右键--选择Builder Path---Add to BiuldPath,即可。这时jar包中的对象,就可以使用了。这样做的好处à项目移动,jar随项目移动。

实例代码1:

import org.apache.commons.beanutils.BeanUtils;  
import org.apache.commons.beanutils.PropertyUtils;  
public class BeanUtilsDemo1  
{  
   public static void main(String[] args) throws Exception  
   {  
      Person p1 = new Person("Ansen", 24);  
//使用BeanUtils的setProperty方法为p1对象的name和age属性设置值       BeanUtils.setProperty(p1,"name","Kandy");  
BeanUtils.setProperty(p1,"age","25");  
//使用BeanUtils的getProperty方法获取p1对象的name和age属性值  
Object obj1 = BeanUtils.getProperty(p1,"name");  
Object obj2 = BeanUtils.getProperty(p1,"age");  
System.out.println(obj1);  
System.out.println(obj2);  
}  
}  

BeanUtils包中其他的Bean操作类

BeanUtils包中还有一个工具类PropertyUtils,用法跟BeanUtils一样。区别:

A.BeanUtils会对JavaBean的属性的类型进行转换,如属性本身是integer,会转换为String。

B.PropertyUtils以属性本身的类型进行操作。

实例1:

Person p = new Person("ZHG",24);  
Object myName = PropertyUtils.getProperty(p,"name");  
System.out.println(myName);  
PropertyUtils.setProperty(p,"age",23);  
Object myAge = PropertyUtils.getProperty(p,"age");  
System.out.println(myAge);  
   PropertyDescriptor d1 = PropertyUtils.getPropertyDescriptor(p,"name");  
   Method setMethod = d1.getWriteMethod();  
   setMethod.invoke(p,"张先生");  
    Method getMethod  = d1.getReadMethod() ;  
System.out.println(getMethod.invoke(p));  

原文链接:http://blog.csdn.net/hua631150873/article/details/11821213

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

[Go语言]实现可以枚举的map

在golang-nuts上看到有人问怎么样去枚举一个map。在go语言层面,并不支持支持枚举map,也就是说你不能获得一个枚举器在任意时刻去枚举这个map,只能...

38470
来自专栏owent

VC和GCC成员函数指针实现的研究(二)

调用的时候主要看(c.*vptr2)()的代码。因为(c.vptr1)()生成的和单继承一样。而由于它们最终都转向vcall,所以vptr2的时候调整了虚表指针...

10420
来自专栏PhpZendo

带你入门 JavaScript ES6 (五) 集合

本章我们将学习 ES6 中的 Set(集合) 及 WeakSet 集合 的相关用法及使用场景。

10720
来自专栏阿杜的世界

Java泛型基础(二)泛型接口泛型方法# 总结

泛型可以应用于同一个类,该类可以针对多种类型使用,例如构建一个RedisTemplateService组件,用于处理当前应用中所有对象的缓存操作。这篇文章主要介...

1.2K30
来自专栏xingoo, 一个梦想做发明家的程序员

Oozie分布式工作流——EL表达式

oozie支持使用EL(expression language)表达式。 基本的EL常量 KB MB GB TB PB 基本EL函数 string fir...

27380
来自专栏牛肉圆粉不加葱

[6] - 类和对象之进阶(二)

Scala 中的可见性非常灵活且复杂,这篇文章希望通过大量的示例来说清楚各种情况下的可见性是怎么样的。

7420
来自专栏Golang语言社区

[Go语言]实现可以枚举的map

在golang-nuts上看到有人问怎么样去枚举一个map。在go语言层面,并不支持支持枚举map,也就是说你不能获得一个枚举器在任意时刻去枚举这个map,只能...

37270
来自专栏偏前端工程师的驿站

(cljs/run-at (->JSVM :browser) "语言基础")

前言  两年多前知道cljs的存在时十分兴奋,但因为工作中根本用不上,国内也没有专门的职位于是搁置了对其的探索。而近一两年来又刮起了函数式编程的风潮,恰逢有幸主...

22970
来自专栏编程

使用dict和set

Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。-...

231100
来自专栏余林丰

多个构造器参数使用构建器

标题一眼看过去可能不是很明白要讲什么,先来看看下面一段代码。 1 package example; 2 3 /** 4 * 重叠构造器 5 * ...

20480

扫码关注云+社区

领取腾讯云代金券