框架 = 注解 + 反射 + 设计模式
1. 注解概述
注解(Annotation
)是从JDK5.0开始引入,以“@注解名”在代码中存在。
Annotation 可以像修饰符一样被使用,可用于修饰包、类、构造器、方法、成员变量、参数、局部变量的声明。还可以添加一些参数值,这些信息被保存在 Annotation 的 “name=value” 对中。
注解可以在类编译、运行时进行加载,体现不同的功能。
2. 注解与注释
注解也可以看做是一种注释,通过使用 Annotation,可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。但是,注解,不同于单行注释和多行注释。
- 对于单行注释和多行注释是给程序员看的。
- 而注解是可以被编译器或其他程序读取的。程序还可以根据注解的不同,做出相应的处理。
3. 注解的重要性
在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。
未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,Struts2有一部分也是基于注解的了。
4. 常见的Annotation作用
4.1 生成文档相关的注解
@author
: 标明开发该类模块的作者,多个作者之间使用,分割
@version
: 标明该类模块的版本
@see
: 参考转向,也就是相关主题
@since
: 从哪个版本开始增加的
@param
: 对方法中某参数的说明,如果没有参数就不能写
@return
: 对方法返回值的说明,如果方法的返回值类型是void就不能写
@exception
: 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写
4.2 在编译时进行格式检查(JDK内置的三个基本注解)
@Override
: 限定重写父类方法,该注解只能用于方法
- 用于检测被标记的方法为有效的重写方法,如果不是,则报编译错误!
- 只能标记在方法上。
- 它会被编译器程序读取。
@Deprecated
: 用于表示所修饰的元素(类,方法等)已过时。通常是因为所修饰的结构危险或存在更好的选择
- 用于表示被标记的数据已经过时,不推荐使用。
- 可以用于修饰 属性、方法、构造、类、包、局部变量、参数。
- 它会被编译器程序读取。
@SuppressWarnings
: 抑制编译器警告 - 抑制编译警告。当我们不希望看到警告信息的时候,可以使用
SuppressWarnings
注解来抑制警告信息 - 可以用于修饰类、属性、方法、构造、局部变量、参数
- 它会被编译器程序读取。
- 可以指定的警告类型有(了解)
all
,抑制所有警告unchecked
,抑制与未检查的作业相关的警告unused
,抑制与未用的程式码及停用的程式码相关的警告deprecation
,抑制与淘汰的相关警告nls
,抑制与非 nls 字串文字相关的警告null
,抑制与空值分析相关的警告rawtypes
,抑制与使用 raw 类型相关的警告static-access
,抑制与静态存取不正确相关的警告static-method
,抑制与可能宣告为 static 的方法相关的警告super
,抑制与置换方法相关但不含 super 呼叫的警告- …
5. 元注解
JDK1.5在java.lang.annotation包定义了4个标准的meta-annotation
类型,它们被用来提供对其它 annotation类型作说明。
(1)@Target
:用于描述注解的使用范围
- 可以通过枚举类型
ElementType
的10个常量对象来指定 - TYPE,METHOD,CONSTRUCTOR,PACKAGE…
(2)@Retention
:用于描述注解的生命周期
- 可以通过枚举类型
RetentionPolicy
的3个常量对象来指定 - SOURCE(源代码)、CLASS(字节码)、RUNTIME(运行时)
- 唯有RUNTIME阶段才能被反射读取到。
(3)@Documented
:表明这个注解应该被 javadoc工具记录。
(4)@Inherited
:允许子类继承父类中的注解
示例代码:
package java.lang; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
package java.lang; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
package java.lang; import java.lang.annotation.*; import static java.lang.annotation.ElementType.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}) public @interface Deprecated { }
6. 自定义注解
一个完整的注解应该包含三个部分: (1)声明
、 (2)使用
、 (3)读取
声明自定义注解:
【元注解】 【修饰符】 @interface 注解名{ 【成员列表】 }
- 自定义注解可以通过四个元注解
@Retention
,@Target
,@Inherited
,@Documented
,分别说明它的声明周期,使用位置,是否被继承,是否被生成到API文档中。 Annotation
的成员在Annotation
定义中以无参数有返回值的抽象方法的形式来声明,我们又称为配置参数。返回值类型只能是八种基本数据类型、String
类型、Class
类型、enum
类型、Annotation
类型、以上所有类型的数组- 可以使用
default
关键字为抽象方法指定默认返回值 - 如果定义的注解含有抽象方法,那么使用时必须指定返回值,除非它有默认值。格式是“方法名 = 返回值”,如果只有一个抽象方法需要赋值,且方法名为value,可以省略“value=”,所以如果注解只有一个抽象方法成员,建议使用方法名value。
6.1 定义自定义注解
import java.lang.annotation.*; @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String value(); }
import java.lang.annotation.*; @Inherited @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String columnName(); String columnType(); }
6.2 使用自定义注解
@Table("t_stu") public class Student { @Column(columnName = "sid",columnType = "int") private int id; @Column(columnName = "sname",columnType = "varchar(20)") private String name; }
6.3 读取和处理自定义注解
自定义注解必须配上注解的信息处理流程才有意义。
自己定义的注解,只能使用反射的代码读取。所以自定义注解的声明周期必须是RetentionPolicy.RUNTIME
。