黑马程序员-->Java基础加强-->内省(Introspector)与注解(Annotation)

来源:互联网 发布:剑网三优化版补丁 编辑:程序博客网 时间:2024/06/08 11:42

-------android培训java培训、期待与您交流! ----------

 

一、什么是内省(Introspector),如何了解JavaBean

   内省,字面意思就是内窥,内部检查。在Java中代表了解更多的底层细节。主要作用于对Javabean进行操作。
那么,JavaBean是什么?

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

   例如类A中有属性name, 那我们可以通过getName,setName来得到其值或者设置新的值。通过 getName/setName来访问name属性,这就是默认的规则。Java 中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中,一般的做法是通过类Introspector的getBeanInfo方法来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。

   如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO),因为这些bean中通常只有一些信息字段和存储方法,没有功能性方法。
JavaBean通过提供符合一致性设计模式的公共方法将内部域暴露成员属性。众所周知,属性名称符合这种模式,其它Java类可以通过自身机制发现和操作这些JavaBean属性。
   通俗理解就是,这些信息在类中用私有字段来存储,如果读取或者设置这些字段的值,则需要通过一些相应的方法来访问。JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,不需要知道!去掉set前缀,剩余部分是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首写字母改成小的。下面举个例子:

setId()的属性名->id
isLast()的属性名->last
setCPU的属性名->CPU
getUPS的属性名->UPS

总之,一个JavaBean类可以当成普通类用,但是一个java类不一定能当做JavaBean。因为JavaBean实际就是一种规范,当一个类满足这个规范,这个类就能被其它特定的类调用。一个类被当作JavaBean使用时,JavaBean的属性是根据方法名推断出来的,根本看不到Java类内部的成员变量。

一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当作JavaBean用肯定需要带来一些额外的好处,我们才会去了解和应用JavaBean!好处如下:
在Java EE开发中,经常要使用JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么选择的余地!
JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的,怎么做,有一定难度吧?用内省这套API操作JavaBean比用普通类的方式更方便,提高代码重用性,提高开发效率。

 

二、JavaBean的特点

JavaBean有三个特性:
1、javaBean必须是一个具体的public的类
2、JavaBean有一个不带参数的构造函数,如果public类的构造函数包含参数的话,那这个类不能做为JavaBean
3、JavaBean通过 getProperty获取属性,通过setProperty设置属性

 

三、对JavaBean的简单内省操作

代码演示:

 

 

下面是Eclipse的使用技巧:代码抽取,封装成一个函数

总结:只是获取某个JavaBean类的某个属性,可以通过PropertyDescriptor来创建对象,
传入JavaBean的属性名,指定的字节码类,以及根据情况传入参数(set方法需要)。
通过反射机制,调用相应的读写获取或者设置相应的属性值。

 

四、对JavaBean的复杂内省操作

代码示例:(对简单操作代码的修改)

总结:复杂的JavaBean操作方式,通过BeanInfo这个类来描述,调用Introspector的静态方法getBeanInfo,
将指定类看做JavaBean。通过getPropertyDescriptors方法获取属性描述数组对象。
最后从数组中取得一个个的属性对象进行操作。通过反射机制,调用或者相应获取或者设置的读写方法。

 

五、如何使用BeanUtils工具包操作JavaBean

1、如何安装需要的BeanUtils工具包

下载需要的BeanUtils工具包和logging

在工程根目录中new一个folder文件夹将需要的工具jar包放进来(Ctrl+V),如下

2、下面是代码演示使用BeanUtils工具包

总结:BeanUtils 和 PropertyUtils 的区别:
BeanUtils是以字符串的形式对JavaBean进行操作(属性本身会有类型转换);
PropertyUtils是以那个属性本身的类型对JavaBean进行操作(属性本身类型不变)。

 

六、什么是注解(Annotation)

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


七、了解java内置的三种基本的注解:

注解的语法比较简单,除了@符号的使用以外,它基本上与java的固有语法一致,java内置了三种注解,定义在java.lang包中。

(1)@SuppressWarnings 表示关闭一些不当的编译器警告信息。
代码示例:

小结:在main方法上添加一个注解:@SuppressWarnings("deprecation"),此注解的作用就是告诉编译器,
虽然我用的方法过时了,但是我还是坚持要用,你就不要再提示了。此时划线的代码左边的三角形警告符号就消失了。

 

通过命令行进行编译也可以看到过时的提示,如下:

 

加了注释@:@SuppressWarnings("deprecation"),再在命令行窗口中进行编译,就不会出现过时提示了。

 

(2)@Deprecated  表示当前元素已过时,不赞成或者不建议使用的。
代码示例:

小结:由上面的示例可以看到,我们的sayHello方法可以通过@Deprecated注解标记为过时,
然后调用者调用该方法的地方就会被eclipse划上横线作为过时的提示。如下调用就会出现警告和划线。

 

(3)@Override  表示当前方法是覆盖父类的方法。
代码示例:
equals方法的参数为Object obj,但是经常会被写错,这时候就可以通过@Override注解避免这种情况

小结:有时候我们写的某些方法需要覆盖父类的方法,但是可能方法名或者参数会出现不小心写错的情况。
这时候就可以为这个方法打上@Override注解,如果有任何差错,eclipse就会报错。
正确应该为:

总结:
1、注解是JDK1.5的新特性
2、一个注解就是一个类,使用注解,就相当于创建该类的实例对象。

 

八、注解的定义与反射的调用

 

 

代码演示:
A类:ItcastAnnotation

B类:AnnotationTest

小结:执行之后,控制台并没有打印出任何信息,原因是因为@ItcastAnnotation注解的RetentionPolicy元注解默认值是RetentionPolicy.CLASS,也就是说@ItcastAnnotation注解在运行的时候已经被过滤掉了。解决这个问题的方式就是将@ItcastAnnotation的RetentionPolicy元注解值设置为RetentionPolicy.RUNTIME。如下:

A类:ItcastAnnotation

B类运行结果:AnnotationTest

小结:
元注解就是在注解上添加的注解。
@Retention元注解有三种取值:RetetionPolicy.SOURCE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIME,
 分别对应:java源文件-->class文件-->内存中的字节码。一般注解默认的生命周期是RetetionPolicy.CLASS。
java内置的注解@Override、@SuppressWarnings和@Deprecated这三个注解的@Retention元注解的value属性值分别是什么?
@Override:编译器看源程序中有没有重写,没有就报错,所以@Override的生命周期是value=SOURCE
@SuppressWarnings:给编译器看,这个方法虽是过时的,当我还是要用不要提示警告,所以@SuppressWarnings的生命周期是value=SOURCE
@Deprecated:编译器看到的这个方法是以二进制的字节码文件存在,判断出来是过时的,所以@Deprecated的生命周期是value=RUNTIME

 

Target的默认值为任何元素,如果设置Target等于ElementType.METHOD,原来加在类上的注解就报错了。
代码示例:

改为用数组方式设置{ElementType.METHOD,ElementType.TYPE}就不会报错了。如下:

小结:这里为何用TYPE而不是Class?因为Class类的父类是TYPE,有些类像似Class类又不是,而是跟Class平级,
比如:interface、enum、@interface,都表示java的类型,而用来描述这类事物的类,叫做TYPE,属于JDK1.5的新特性。

 

九、如何为注解增加各种属性

1、什么是注解的属性
打个比方说:
一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是黑马的学生,否则,就不是。如果还想区分出是黑马哪个班的学生,
这时候可以为胸牌再增加一个属性来进行区分。
加了属性的标记效果为:@ItcastAnnotation(color="red")。
2、定义基本类型的属性和应用属性:
在注解类中增加String color();被添加的注解设置属性值:@ItcastAnnotation(color="red")
3、用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
ItcastAnnotation annotation  = (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);
System.out.println(annotation.color());
可以认为上面这个@ItcastAnnotation是ItcastAnnotation类的一个实例对象。
4、为属性指定缺省值:
String color() default "blue";
5、value属性:String value() default "zxx";
如果注解中有一个名称为value的属性,且你只想设置value属性(即其它属性都采用默认值或者你只有一个value属性),
那么可以省略“value=”部分,例如:@ItcastAnnotation("xyz")
6、数组类型的属性
int[ ] arrayAttr() default {1,2,2};被添加的注解设置属性值:@ItcastAnnotation(arrayAttr={2,3,4})。
 如果数组属性中只有一个元素,这时候属性值部分可以省略大括号,如:@ItcastAnnotation(arrayAttr = 2)
7、枚举类型的属性
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.RED ;
被添加的注解设置属性值:@ItcastAnnotation(lamp = EnumTest.TrafficLamp.GREEN
8、注解类型的属性:
MetaAnnotation annotionAttr() default @MetaAnnotation("java");
被添加的注解设置属性值:@ItcastAnnotation(annotionAttr = @MetaAnnotation("heima"))
9、class类型的属性:
Class clazz() default String.class;
被添加的注解设置属性值:@ItcastAnnotation(clazz = int.class)

代码示例:
   MetaAnnotation类:


   ItcastAnnotation类

   AnnotationTest类:

运行结果:
red
abc
1
YELLOW
heima
int
总结:对于为注解增加属性,注解类似于接口,属性类似于抽象方法;
设置的时候以属性的形式设置,取值的时候以方法的形式调用,返回设置时的属性值。
注解的属性类型包括:8个基本数据类型,String,Class,枚举,其它注解,以及这些类型的数组。

-------android培训java培训、期待与您交流! ----------

0 0
原创粉丝点击