1.注解(Annotation)的概念:
我们可以把注解理解成"标签",这个"标签"我们可以贴在packages(包),class(类),interface(接口),enum(举),Annotation(注解),method(法),construct(构造方法),member(成员变量),parameter(方法参数),variable(本地变量:环变量、catch参数)。通过这些标签,结合反射,可以找到任我们想要的元素。2.注解的分类:
初次接触Java后,在编程过程中,我们经常会发现一些诸如@Override,@SuppressWarnnings的注解,没错,这些是JDK系统内置的一些注解
。我们根据注解使用方法和用途,大致可以将Annotation分为三类:
①.JDK系统内置注解
②.元注解
③.自定义注解
2.1.常见的JDK系统内置注解:
JavaSE中内置三个标准注解,定义在java.lang中:@Override:用于修饰此方法覆盖了父类的方法;
@Deprecated:用于修饰已经过时的方法;
@SuppressWarnnings:用于通知java编译器禁止特定的编译警告。
@Override
@Override用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用,如果我们使用了这种Annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示,例如:
public class People{
private String name;
public void setName(){
this.name = "人";
System.out.println("父类");
}
}
public class Student extends People{
@Override
public void setName(){
this.name = "学生";
System.out.println("学生子类");
}
}
public class Teacher extends People{
//注意settName与setName的不同
@Override
public void settName(){
this.name = "教师";
System.out.println("教师");
}
}
Student 类编译不会有任何问题,Teacher类在编译的时候会提示相应的错误。注意:@Override注解只能用于方法,不能用于其他程序元素。
@Deprecated
当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要报警。例如:
/**
* @deprecated 该方法已经过期,不推荐使用
*/
@Deprecated
public void showType(){
System.out.println("教师");
}
上述代码片中,注释中的 @deprecated标签是用来被javadoc工具所识别用来生成文档的,而@Deprecated才是用来注解表示方法过期的,jdk1.5以后我们应该使用@Deprecated来修饰过时的方法而不是 @deprecated javadoc tag。
@SuppressWarnnings
抑制编译器警告。@SuppressWarnings用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。例如关闭泛型转换时的警告,关闭没有被调用的成员方法警告等,annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对用于为annotation的成员赋值,SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。例如:
public class StudentManager {
@SuppressWarnings(value={ "rawtypes", "unchecked" })
public static List<Student> getStudentList(){
List<Student> studentList=new ArrayList();
return studentList;
}
@SuppressWarnings("unused")
public static void main(String[] args){
List<String> strList=new ArrayList<String>();
}
}
SuppressWarnings注解的常见参数值的简单说明:
1.deprecation:使用了不赞成使用的类或方法时的警告;
2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型(Generics) 来指定集合保存的类型;
3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
4.path:在类路径、源文件路径等中有不存在的路径时的警告;
5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
6.finally:任何 finally 子句不能正常完成时的警告;
7.all:关于以上所有情况的警告。
2.2.元注解
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:@Target,@Retention,@Documented,@Inherited。这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们来看看整体的这几种注解的使用:
@Target
@Target说明了Annotation所修饰的对象范围:取值(ElementType)有:
1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明
使用实例:
<span style="white-space:pre"> </span>@Target(ElementType.TYPE)
public @interface Table {
//表名
public String tableName() default "className";
}
@Target(ElementType.FIELD)
public @interface Column {
}
上述代码中,注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解Column仅可用于注解类的成员变量。
@Retention
@Retention定义了该Annotation被保留的时间长短,可以对Annotation的“生命周期”限制。取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
Retention 类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:
<span style="white-space:pre"> </span>@Target(ElementType.FIELD)
<span style="white-space:pre"> </span>@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}
上述代码中:Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理。
@Documented
Documented是一个标记注解,没有成员。用来将该注解信息可以被 javadoc 之类的工具处理,表明这个注解应该被 javadoc工具记录. 默认情下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。例如:
<span style="white-space:pre"> </span>@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column {
public String name() default "fieldName";
public String setFuncName() default "setField";
public String getFuncName() default "getField";
public boolean defaultDBValue() default false;
}
@Inherited
Inherited元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。注意:①.@Inherited annotation类型是被标注过的class的子类所继承。 但类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。②.当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类 继承结构的顶层。例如:
<span style="white-space:pre"> </span>@Inherited
public @interface MyParentObject {
boolean isInherited() default true;
String doSomething() default "Do what?";
}
接下来,使用注解标注了一个类:
<span style="white-space:pre"> </span>@MyParentObject
public Class MyChildObject {
}
不需要在实现类中定义接口方法. 因为使用 @Inherited标记,这些都自动继承了. 如果用传统的实现方法:
<span style="white-space:pre"> </span>public class MyChildObject implements MyParentObject {
public boolean isInherited() {
return false;
}
public String doSomething() {
return "";
}
public boolean equals(Object obj) {
return false;
}
public int hashCode() {
return 0;
}
public String toString() {
return "";
}
public Class annotationType() {
return null;
}
}
可以看到,必须实现父接口的所有方法. 除了isInherited()和从myParentObject doSomething()方法外,你还需要实现 java.lang.Object的 equals(),toString()和hasCode()方法. 还有 java.lang.annotation.Annotation 类的 annotationType()方法. 不管你是不是想要实现这些方法,你必须在继承的对象中包含这些。
3.总结:
更详细的注解介绍可以参考http://my.oschina.net/hongdengyan/blog/179732。
下一篇我们将重点介绍自定义注解的灵活使用。