- Annotation(注释) 概述
从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是 Annotation(注释)
Annotation 其实就是代码里的特殊标记, 这些标记可以在编译, 类加载, 运行时被读取, 并执行相应的处理. 通过使用 Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息。Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在
Annotation 的 “name=value” 对中。Annotation 能被用来为程序元素(类, 方法, 成员变量等) 设置元数据
- 为什么使用注解
1,注解使得我们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息
2,以用来生成描述符文件,甚至或是新的类定义,并且有助于减轻
3,更加干净易读的代码以及编译器类型检查编写样板代码的负担
- JDK内置注解
使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用. 用于修饰它支持的程序元素,三个基本的 Annotation:
@Override: 限定重写父类方法, 该注释只能用于方法,表示一个方法声明打算重写超类中的另一个方法声明。
@Deprecated: 用于表示某个程序元素(类, 方法等)已过时,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择
@SuppressWarnings: 抑制编译器警告。
package linkin; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List; /**
*
* @version 1L
* @author LinkinPark
* @since 2014-11-27
* @motto 梦似烟花心似水,同学少年不言情
* @desc ^3个常用的注解
*/
@SuppressWarnings("all")
public class Linkin
{ @Override
public String toString()
{
return "";
} public void test()
{
Date date = new Date();
int year = date.getYear();
int year1 = Calendar.getInstance().get(Calendar.YEAR);
} @SuppressWarnings("unchecked")
public void test1()
{
List<String> linkin = new ArrayList();
} }
- 自定义 Annotation
修饰符 @interface 名{
类型 元素名() [default value]
}
定义新的 Annotation 类型使用 @interface 关键字。Annotation 的成员变量在 Annotation 定义中以无参数方法的形式来声明. 其方法名和返回值定义了该成员的名字和类型。可以在定义 Annotation 的成员变量时为其指定初始值, 指定成员变量的初始值可使用 default 关键字。没有成员定义的 Annotation 称为标记; 包含成员变量的 Annotation 称为元数据 Annotation
package linkin; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
*
* @version 1L
* @author LinkinPark
* @since 2014-11-27
* @motto 梦似烟花心似水,同学少年不言情
* @desc ^如果Annotation的成员变量名为value的时候,程序中可以直接在Annotation后面的括号里面指定该成员变量的值,无须使用name=value的形式
*/
//如果要指定多个作用域,可以传入一个数组@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
@Target(ElementType.METHOD)
//一般都是RUNTIME,来运行时通过反射也可以获得这个注解。@Retention(value=RetentionPolicy.RUNTIME)
@Retention(RetentionPolicy.RUNTIME)
public @interface LinkinAnnotation {
String value() default "";
String name() default "";
String[] names();
}
- JDK 的元 Annotation
JDK 的元 Annotation 用于修饰其他 Annotation 定义
1,@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值:
RetentionPolicy.CLASS: 编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注释. 这是默认值
RetentionPolicy.RUNTIME:编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注释. 程序可以通过反射获取该注释
RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释
2,@Target: 用于修饰 Annotation 定义, 用于指定被修饰的 Annotation 能用于修饰哪些程序元素. @Target 也包含一个名为 value 的成员变量
3,@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档
4,@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注释。
上面的元注解经常用到就下面2个:@Target 该注解可以用于哪些地方。@Retention 表示需要在什么级别保存该注解信息
- 提取 Annotation 信息
JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 接口, 该接口代表程序中可以接受注释的程序元素
当一个 Annotation 类型被定义为运行时 Annotation 后, 该注释才是运行时可见, 当 class 文件被载入时保存在 class 文件中的 Annotation 才会被虚拟机读取
程序可以调用 AnnotationElement 对象的如下方法来访问 Annotation 信息。
- 什么是注解处理器
注解本身并不会对程序的编译方式产生影响。注解处理器能够通过在运行时使用反射获取在程序代码中的使用的注解信息,从而实现一些额外的功能。
下面的代码模拟演示juit测试框架:
package com.tanlan.crm.base.ap; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method; /**
*
* @version 1L
* @author LinkinPark
* @since 2014-11-27
* @motto 梦似烟花心似水,同学少年不言情
* @desc ^模拟juit测试框架,即打了test注解的方法能被执行
*/
public class AnnoatationProcess {
public void process(TestDemo testDemo) throws Exception {
Class<TestDemo> c = TestDemo.class;
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
// 判断方法是否使用了Test注解
if (method.isAnnotationPresent(Test.class)) {
method.invoke(testDemo);
}
}
} public static void main(String[] args) throws Exception {
TestDemo testDemo=new TestDemo();
AnnoatationProcess process=new AnnoatationProcess();
process.process(testDemo);
}
} @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Test { } class TestDemo {
@Test
public void test1() {
System.out.println("test1");
} @Test
public void test2() {
System.out.println("test2");
}
}
下面代码模拟了hibernate的实体注解映射:
package com.tanlan.crm.base.ap; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Method; public class DAO { public void add1(User user) throws Exception {
String sql = "insert into ";
String values = "";
Class<User> c = User.class;
if (c.isAnnotationPresent(Table.class)) {
Table t = c.getAnnotation(Table.class);
String tableName = t.value();
if (tableName.equals("")) {
tableName = c.getSimpleName();
}
sql += tableName + "(";
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Column.class)) {
Column col = field.getAnnotation(Column.class);
String colName = col.value();
if (colName.equals("")) {
colName = field.getName();
}
sql += colName + ",";
Method method = c.getDeclaredMethod("get"
+ toUpper(colName));
Object v = method.invoke(user);
values += "'" + v + "',";
}
}
}
sql = sql.substring(0, sql.length() - 1);
sql += ") values(" + values.substring(0, values.length() - 1) + ")";
System.out.println(sql);
} public <E> void add(E e) throws Exception {
String sql = "insert into ";
String values = "";
Class<?> c = e.getClass();
if (c.isAnnotationPresent(Table.class)) {
Table t = c.getAnnotation(Table.class);
String tableName = t.value();
if (tableName.equals("")) {
tableName = c.getSimpleName();
}
sql += tableName + "(";
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Column.class)) {
Column col = field.getAnnotation(Column.class);
String colName = col.value();
if (colName.equals("")) {
colName = field.getName();
}
sql += colName + ",";
Method method = c.getDeclaredMethod("get"
+ toUpper(colName));
Object v = method.invoke(e);
values += "'" + v + "',";
} } }
sql = sql.substring(0, sql.length() - 1);
sql += ") values(" + values.substring(0, values.length() - 1) + ")";
System.out.println(sql);
} private static String toUpper(String s) {
String first = s.substring(0, 1);
return first.toUpperCase() + s.substring(1);
} public static void main(String[] args) throws Exception {
User user=new User();
user.setName("Tom");
user.setPassword("123456"); DAO dao=new DAO();
dao.add(user); Product product=new Product();
product.setName("电视");
dao.add(product); }
} @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table {
String value() default ""; } @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Column {
String value() default "";
} @Table
class User {
@Column("name")
private String name;
@Column
private String password; 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;
} } @Table("crm_product")
class Product {
@Column
private String name; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} }