2010年Java高新技术A(3)内省 JavaBean 注解

时间:2021-05-02 19:08:44

1 什么是javaBean

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

2 javaBean有什么作用

       如果要在两个模块之间传递多个信息,可以讲这些信息封装到一个javaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object 建成VO)。这些信息在类中用私有字段来存数,想要获取这些信息可以通过一定的方法来获取。

3 如何获取JavaBean中的信息

       JavaBean中的属性是根据其中的getter和setter方法确定的,并不是根据其中的成员变量,如果方法名为setId,中文意思即为设置 ID,至于把它存在哪个变量上,无所谓都是表示设置ID 同样如果方法名字为getID 中文意思即为获取ID至于从哪个变量上去,无所谓都是表示取ID,一般按照如下规则命名 去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的

如setId()àid; isLast()àlast;  setCPU—>CPU;      getupsàUPS;

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

4     JavaBean的好处

       在JavaEE开发中,经常要使用JavaBean,很多环境就要求按JavaBean方式进行操作,主流。

       JDK中提供了对JavaBean进行操作的一些API,这些API就称为内省,如果要你自己去通过getX 方法来访问私有的X是由一定难度的,用内省这套API操作JavaBean比普通类的方式要方便。

 5示例对JavaBean的操作

 

  1. package cn.itheima.fanshe;  
  2.   
  3. import java.beans.PropertyDescriptor;  
  4. import java.lang.reflect.Method;  
  5.   
  6. public class beantest {  
  7.   
  8.       
  9.     public static void main(String[] args) throws Exception{  
  10.         //通过bean方式获取对象 rd1的name值  
  11.         RoleDemo rd1 = new RoleDemo("张三","type1");  
  12.         //定义一个要获取的属性名 这个是name  
  13.         String propertyName = "name";  
  14.         //获取属性 参数 指定要获取的属性,和指定的类  
  15.         PropertyDescriptor pd = new PropertyDescriptor(propertyName,rd1.getClass());  
  16.         //得到属性了 进一步就可以得到属性的get set方法 如下即可得到了X属性的读方法  
  17.         Method methodgname = pd.getReadMethod();  
  18.         //有了这个属性的读方法我们就可以用这个方法在rd1方法上调用。  
  19.         Object retval   = methodgname.invoke(rd1);  
  20.         System.out.println(retval);  
  21.         //输出 调用了带两个属性的构造器 张三  
  22.           
  23.         Method methodsname = pd.getWriteMethod();  
  24.         //有了这个属性的读方法我们就可以用这个方法在rd1方法上调用。  
  25.         Object retval1   = methodsname.invoke(rd1,"李四");  
  26.         System.out.println(rd1.getName());  
  27.         //输出 李四  
  28.           
  29.     }  
  30.   
  31. }  

可以到上面获取属性值的时候有代码复用,那么可以抽取出来构成一个方法,用的时候调用即可

  1. package cn.itheima.fanshe;  
  2.   
  3. import java.beans.IntrospectionException;  
  4. import java.beans.PropertyDescriptor;  
  5. import java.lang.reflect.InvocationTargetException;  
  6. import java.lang.reflect.Method;  
  7.   
  8. public class beantest {  
  9.   
  10.       
  11.     public static void main(String[] args) throws Exception{  
  12.         //通过bean方式获取对象 rd1的name值  
  13.         RoleDemo rd1 = new RoleDemo("张三","type1");  
  14.         //定义一个要获取的属性名 这个是name  
  15.         String propertyName = "name";  
  16.           
  17.         Object retval = getProperty(rd1, propertyName);  
  18.         System.out.println(retval);  
  19.         Object newVal = "李四";  
  20.         //输出 调用了带两个属性的构造器 张三  
  21.   
  22.         getProperts(rd1, propertyName, newVal);  
  23.         System.out.println(rd1.getName());  
  24.         //输出 李四  
  25.           
  26.     }  
  27.     private static void getProperts(Object rd1, String propertyName,  
  28.             Object newVal) throws IntrospectionException,  
  29.             IllegalAccessException, InvocationTargetException {  
  30.         PropertyDescriptor pd = new PropertyDescriptor(propertyName,rd1.getClass());  
  31.         Method methodsname = pd.getWriteMethod();  
  32.         Object retval1   = methodsname.invoke(rd1,newVal);  
  33.     }  
  34. //重构的方法  
  35.     private static Object getProperty(Object rd1, String propertyName)  
  36.             throws IntrospectionException, IllegalAccessException,  
  37.             InvocationTargetException {  
  38.         PropertyDescriptor pd = new PropertyDescriptor(propertyName,rd1.getClass());  
  39.         Method methodgname = pd.getReadMethod();  
  40.         Object retval   = methodgname.invoke(rd1);  
  41.         return retval;  
  42.     }  
  43.   
  44. }  

 

对JavaBean的复杂内省操作:在IntroSpector类中有getBeanInfo(Class cls)的方法。

获取Class对象的Bean信息,返回的是BeanInfo类型。

BeanInfo类中有getPropertyDescriptors()的方法,可获取所有的BeanInfo的属性信息,返回一个PropertyDescriptor[]。

在通过遍历的形式,找出与自己想要的那个属性信息。

如:改写get方法:

  1. ...  
  2. BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());    
  3.         PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();    
  4.         Object value = null;    
  5.         for(PropertyDescriptor pd : pds){    
  6.             if(pd.getName().equals(propertyName)){    
  7.                 Method methodGetX = pd.getReadMethod();    
  8.                 value = methodGetX.invoke(pt1);    
  9.                 break;    
  10.             }    
  11.         }    
  12. …    

 

6    Beanutils工具包

       为了便于操作JavaBean,前辈们就编写了BeanUtils包,里面封装了很多对JavaBean的操作,我们在用的时候可以直接拿过来用。

好处是什么呢有如下三个好处

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

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

       一是 可以和Map集合进行相互转换,可以讲属性信息通过键值对的形式作为Map集合存储(通过 staticJava.util.Mapdecribe(java.lang.Objectbean)的方法)也可以讲Map集合转换为JavaBean 中的属性信息,(通过static void populate(java.lang.object bean,java.util.map properties)的方法)。

上面我们介绍了通过bean方式获取对象 rd1的name值的方法,下面我们可以利用BeanUtils包简化操作

  1. //通过bean方式获取对象 rd1的name值  
  2.         RoleDemo rd1 = new RoleDemo("张三","type1");  
  3.         //定义一个要获取的属性名 这个是name  
  4.         String propertyName = "name";  
  5. System.out.println(BeanUtils.getProperty(rd1, propertyName));  
  6.         BeanUtils.setProperty(rd1, propertyName, "李四");  
  7.         System.out.println(rd1.getName());  
  8. 输出张三 李四 显然简化了操作  

 

注解

java提供的几个基本注解

1、  @suppressWarning(“deprecation”)à压制警告

       suppressWaring是告知编译器或开发工具等提示指定的编译器警告

       deprecation 是告知具体的信息即方法已过时

2、  @Deprecatedà提示成员已经过时,不再推荐使用。

       源代码标记@Deprecated是在JDK1.5中作为内置的annotatin引入的,用于表明类、方法、字段已经不再推荐使用,并且在以后的JDK 版本中,可能将其删除,在编译器在默认情况下检测到此标记时,会提示警告信息:假如之前的某个类升级了,其中的某个方法已经过时了,不能够将过时的方法删 除,因为可能会影响到调用此类的这个方法的某些程序,这是就可以通过在方法上加这个注解。

3、@Overrideà提示覆盖(父类方法)

加上此注解,可对自己类中的方法判断是否是要覆盖的父类的方法,典型的例子即在集合中覆盖equals(Object obj)方法,其中的参数类型必须是Object,才能被覆盖,若不是,加上此注解就会提示警告。

总结

       注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后javac编译器,开发工具盒其他程序可以用反射来了 解你的类及各种元素上有无何种标记,看你有什么标记就去干相应的事,标记可以加在包,类,字段,方法,方法的参数上以及局部变量上

4、  自定义注解

       自定义注解和接口差不都 ,只是在interface前面加一个@

public @interface Myannotation {} 这个代码是一个最简单的注解,这个注解没有属性,也可以理解为是一个标记注解。就像Serlializable接口一样是一个标记接口,里面未定义方法。 也可以再里面加上方法public @interface MyAnnotation{String value() }

       使用子低昂一注解

       @MyAnnotation(“abc”)

       publicvoid myMethod(){}

这里的abc传给了Value 有个规定就是如果没有属性名称的值,而这个注解有有Value属性,就将这个值赋给Value属性,如果没有,就出现编译错误。

 

在使用的时候出了可以省略属性值,还可以使用默认值

  1. public @interface MyAnnotation  
  2. {  
  3.     public String MyMethod() default “abc”;  
  4. }  
  5. //使用默认值  
  6. @MyAnnotation  
  7. public void MyMethod(){}  

5、  对注解进行注解

       为注解提供的注解叫做 元注解  这种注解主要是 Target Retention Documented 和 Inherited

1)  Target

target表示目标,这个注解在用的时候是与某一些目标相关的。看如下示例

  1.  @Target({ElementType.METHOD})  
  2. @interface MyAnnotation{}  
  3. @MyAnnotation //放在类上面是错误的  
  4. public class Class1  
  5. {  
  6.     @MyAnnotation  
  7.     public void myMethod1(){}  
  8. }  

上面这段代码定义了一个注解MyAnnotation和一个类Class1,使用MyAnnotation分别对Class1和myMethod1进行注解,编译这段代码是无法通过的,因为@Target({ElementType.METHOD})

指定了使用注解的目标是一个方法而不是其他任何语句元素。。由此看见,target所指定的目标就是java中的语句元素,比如类,接口,方法等。 比如只可以对方法和构造函数进行注解可以写成

@Target({ElementType.METHOD,ElementType.CONSTRUCTOR})

@interfaceMyAnnotation{}

2)  Retention

注解只有在被保存到class文件中才可以被读出来,Retention就是为设置注解是否保存在class文件中而存在的。详细用法如下

//不将注解保存在class文件中,类似 // 一样在编译时被过滤掉

@Retention(RetentionPolicy.SOURCE)

@interface MyAnnotation1{}

//只将注解保存在class文件中,在运用反射读取注解时忽略掉这些注解。

@Retention(RetentionPolicy.CLASS)

@interface MyAnnotation2{}

//将注解保存在class文件中,通过反射也可以读出注解

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnnotation3{}

3)  Documented

这个注解跟文档有关,在默认的情况下使用javadoc自动生成文档时,直接将被忽略掉,如果想在文档中包含注解那必须使用Documented为文档注释,例如

 

  1. @interface MyAnnotation{ }  
  2.     @MyAnnotation  
  3.     class Class1  
  4.     {      
  5.      public void myMethod() { }  
  6.     }  

 

在使用的javadoc为这段代码生成文档时并不将@MyAnnotation包含进去。生成的文档对Class1的描述为 class Class1 extends java.lang.Object

如果这样定义MyAnnotation将会出现另一个结果。

@Documented

@interface MyAnnotation{}

生成文档为

@MyAnnotation

class Class1 extendsjava.lang.Object

 

4)  Inherited

 这个是关于继承方面的元注解,不向protected和public成员都将被子类继承一样,在默认的情况下,父类的注解并不会被子类继承,如果要继承,就必须加上Inherited

  1. @Inherited  
  2. @interface MyAnnotation { }  
  3.   
  4. @MyAnnotation  
  5. public class ParentClass {}  
  6.   
  7. public class ChildClass extends ParentClass { }  
  8. 在以上代码中ChildClass和ParentClass一样都已被MyAnnotation注解了。  

 

6、  通过反射查看注解

       在JDK1.5以后可以通过反射来获取注解了。之前的版本是不可以的。

       想要得到某一个类或接口的租借信息,可以使用下面代码

       Annotationannotation = AnnotationTest.calss.getAnnotation(MyAnnotation.class);

       想要得到全部的注解信息可以用如下方式

       //包括继承的所有注解

       Annotation[]annotations =AnnotationTest.class.getAnnotations();

//不包括继承的所有注解

Annotation[] anntations     = AnnotationTest.class.getDeclaredAnnotations()