Java 基础加强 - JavaBean与内省操作

时间:2021-05-08 19:40:27

Java基础加强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 上进行内省,了解其所有属性、公开的方法和事件。

我们可以使用IntrospectorgetBeanInfo(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));