java基础加强--JavaBean和内省Introspector

来源:互联网 发布:java实现登陆注册 编辑:程序博客网 时间:2024/06/15 10:18

内省(Introspector)是与反射有关的知识,主要对JavaBean进行操作。

那么什么是JavaBean

JavaBean是一个特殊的Java类,这个特殊Java类里面的方法的名称符合某种约定的规则。

比如要获取一个对象上的age属性,获取age属性的方法名必须要写为getAge,并且getAge方法要有返回值。

设置age属性的方法名必须要为setAge,并且setAge方法没有返回值而且还要接收一个参数。

这些方法的前面要么set打头,要么get打头,这就叫符合某种特定的规则,符合这种特定规则的Java类就称为JavaBean

class Person{private int x;public int getAge() {return x;}public void setAge(int age) {this.x = age;}}

以普通Java类来看,这个类有个x名称的成员变量。

外部的人看不到类里面的私有变量,只能看得到你的公有方法,能看到你有个公有方法叫getAge(),他认为你有个age属性。

如果把一个Java类当中JavaBean来看的话,那么这个JavaBean的属性(而不是Java类的属性)

是根据getXXXsetXXX方法的名称来推断出来的。而不是内部的成员变量的名称。

如果把Person类当做一个JavaBean来看,它有一个age名称的属性,而不是x

如果把Person当做JavaBean来操作的话,若要设置属性,设置的是age这个属性。不能说是设置x。因为我们根本就看不到x

因此JavaBean的属性是根据方法名称来的。

------------------

一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean!好处如下:

1、在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!

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

用内省这套api操作JavaBean比用普通类的方式更方便。

------------------

如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的settergetter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。

setId()的属性名->id

isLast()的属性名->last

setCPU的属性名是什么?->CPU

getUPS的属性名是什么?->UPS

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

-----------------------
一个简单的JavaBean

public class Person {  //这么一个类就可以称为javaBean; 用来封装数据的private String name;  //字段对外提供了get或set方法。这个字段才能称之为属性。                      /*一个Bean的属性不由它的字段决定,而由它的set或get方法决定                       * 一个类有几个set或get方法它就有几个属性。                       */private String password;private int age;/** * Object类里有个getClass方法。所以getClass也是Object的属性。 * 所有类都是从Object继承而来。所以getClass也Person的属性。 *//*public String getABC(){  //是属性,程序运行结果有ABC属性return null;}*/public void setABC(char age){//setABC()方法里要带有参数,不然ABC不是属性、程序运行结果没有ABC属性。}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}

-------------------

反射:一个类有多个组成部分,例如成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。


为什么需要内省?(Introspector) 

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

访问JavaBean属性的两种方式:

1、直接调用beansetXXXgetXXX方法。

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

      (1)、通过PropertyDescriptor类操作Bean的属性。

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

-------------------------- 

PropertyDescriptor属性描述

public class PropertyDescriptor
extends FeatureDescriptor

PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。 

构造方法摘要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 对象。方法摘要

Method

getReadMethod()          获得应该用于读取属性值的方法。

 Method

getWriteMethod()          获得应该用于写入属性值的方法。

---------------------------

使用内省的方式对JavaBean进行操作:

需求:用内省的方式来读取JavaBean对象的x属性。

JavaBean

public class Point {private int x;private int y;Point(int x,int y){this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}}

IntrospectorTest:

import java.beans.PropertyDescriptor;import java.lang.reflect.Method;public class IntrospectorTest {public static void main(String[] args) throws Exception {         Point p =  new Point(3,4);         String propertyName = "x";           //PropertyDescriptor构造方法的参数:第一个参数是属性名;第二个参数是要把哪一个Java类当中JavaBean来看         //从JavaBean身上获取属性,pd就代表了JavaBean的属性。         PropertyDescriptor pd = new PropertyDescriptor(propertyName, p.getClass());            //JavaBean的属性是由setXXX和getXXX组合出来的。既然得到了JavaBean的属性,那么进一步就可以得到属性背后的get和set方法                                     Method methodGetX = pd.getReadMethod();// getReadMethod是得到属性的只读的方法getXXX;           Object retVal = methodGetX.invoke(p);//在p对象身上调用get方法,get方法不接收任何参数。         System.out.println(retVal); //3         //取出x的值还是原来反射的那一套,但是简便了很多        // 如果要把一个类当中JavaBean来操作,要取某个属性,一定是通过get方法来取。而要得到属性名对应的get方法是很麻烦的。"x"-->"X"-->"getX"-->methodGetX         //而使用内省的API得到属性的get方法是很简单的,只要把JavaBean和属性名传进去就可以了。就会得到属性对应的get和set方法                  Method methodSetX = pd.getWriteMethod();//getWriteMethod()是得到属性的只写的方法setXXX;         methodSetX.invoke(p,7);//在p对象身上调用set方法,set方法接收一个参数。                  retVal = methodGetX.invoke(p);         System.out.println(retVal);  //7         }}

-------------------

JavaBean的复杂内省操作

内省的入口类(核心类)为:Introspector 

public class Introspector
extends Object

Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。

对于这三种信息,Introspector 将分别分析 bean 的类和超类,寻找显式或隐式信息,使用这些信息构建一个全面描述目标 bean 的 BeanInfo 对象。 

方法摘要

static BeanInfo

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

static BeanInfo

getBeanInfo(Class<?> beanClass, Class<?> stopClass)          在给定的“断”点之下,在 Java Bean 上进行内省,了解其所有属性和公开的方法。

getBeanInfo

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

如果 Java Bean 的 BeanInfo 类以前已经被内省,则从 BeanInfo 缓存中检索 BeanInfo 类。

参数:
beanClass - 将要分析的 bean 类。
返回:
描述目标 bean 的 BeanInfo 对象。
抛出:
IntrospectionException - 如果在内省期间发生异常。
另请参见:
flushCaches(), flushFromCaches(java.lang.Class)

getBeanInfo

public static BeanInfo getBeanInfo(Class<?> beanClass,                                   Class<?> stopClass)                            throws IntrospectionException
在给定的“断”点之下,在 Java Bean 上进行内省,了解其所有属性和公开的方法。

如果 Java Bean 的 BeanInfo 类以前已经基于相同的参数被内省,则从 BeanInfo 缓存中检索 BeanInfo 类。

参数:
beanClass - 将要分析的 bean 类。
stopClass - 从其所在位置开始停止分析的基类。stopClass 或其基类中的所有方法/属性/事件都将在分析中被忽略。
抛出:
IntrospectionException - 如果在内省期间发生异常。

用这个类到底Introspector 省谁?

可以调用它的getBeanInfo(beanClass)。给进去的bean是哪个就省谁。这个方法内部就会对这个Bean内省。省出来后就会把Bean的所有属性封装到一个BeanInfo的对象中(getBeanInfo方法负责返回BeanInfo接口的实例)。拿到这个对象就相当于拿到Bean的所有属性了。接着调用它的 getPropertyDescriptors() 方法就可以拿到每个属性的属性描述器(保存到PropertyDescriptor[] 数组中)。拿到描述器后就可以调用描述器的getReadMethod()方法(获得应该用于读取属性值的方法)得到属性的读方法即得到属性的get方法,就可以get这个属性的值。getWriteMethod()(获得应该用于写入属性值的方法)得到属性的写方法即得到属性的set方法,就可以往属性上设置值。

例子:

JavaBean:

package com.congwiny.introspector;public class Person {  //这么一个类就可以称为javaBean; 用来封装数据的private String name;  //字段对外提供了get或set方法。这个字段才能称之为属性。                      /*一个Bean的属性不由它的字段决定,而由它的set或get方法决定                       * 一个类有几个set或get方法它就有几个属性。                       */private String password;private int age;/** * Object类里有个getClass方法。所以getClass也是Object的属性。 * 所有类都是从Object继承而来。所以getClass也Person的属性。 *//*public String getABC(){  //是属性,程序运行结果有ABC属性return null;}*/public void setABC(char age){//setABC()方法里要带有参数,不然ABC不是属性、程序运行结果没有ABC属性。}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}

测试类Demo1:

package com.congwiny.introspector;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;import org.junit.Test;//使用内省API操作bean属性public class Demo1 {    @Testpublic void test1() throws Exception{//得到所有的属性 //BeanInfo info = Introspector.getBeanInfo(Person.class);//得到bean自己的属性BeanInfo info = Introspector.getBeanInfo(Person.class,Object.class);//砍掉(stop掉)从父类Object继承的属性PropertyDescriptor[] pds = info.getPropertyDescriptors();//得到所有的属性描述for(PropertyDescriptor pd : pds){System.out.println(pd.getName()); //输出类Person所有属性的名字}}//操纵bean的指定属性:age@Testpublic void test2() throws Exception{Person p = new Person();PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);//得到属性的些方法,为属性赋值Method method = pd.getWriteMethod(); //public void setAge(int age) method.invoke(p, 45);//获取属性的值method = pd.getReadMethod();System.out.println(method.invoke(p, null));}//高级点内容:获取当前操作的属性的类型@Testpublic void test3() throws Exception{Person p = new Person();PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);System.out.println(pd.getPropertyType());}}


0 0
原创粉丝点击