10.1 java注解
Annotation
- 注解(Annotation)是从JDK5.0开始引入的新技术。
- 注解不是程序本身,可以对程序作出解释;注解可以在编译,类加载,运行时被读取,并执行相应的处理,以便于其他工具补充信息或者进行部署。
- 注解可以对package(包),class(类),method(方法),field(属性)等使用,相当于给它们添加了额外的辅助信息。
内置注解
- 限定父类重写方法:@Override
当子类重写父类方法时,子类可以加上这个注解,确保子类确实重写了父类的方法。 - 标示已过时:@Deprecated
这个注解用于表示某个程序元素类,方法等已过时,当其他程序使用已过时的类或方法时编译器会给出警告。 - 抑制编译器警告:@SuppressWarnings
被该注解修饰的元素以及该元素的所有子元素取消显示编译器警告,即用来抑制编译时的警告信息。
@SuppressWarnings注解需要添加一个参数才能使用,这些参数值是已经定义好的,可直接使用。
示例:@SuppressWarnings("unchecked")
@SuppressWarnings(value={"unchecked", "deprecation"})
参数如下:
参数 | 说明 |
---|---|
deprecation | 使用了过时的类或方法的警告 |
unchecked | 执行了未检查的转换时的警告,如使用集合时未指定泛型 |
fallthrough | 当在switch语句使用时发生case穿透 |
path | 在类路径、源文件路径中有不存在路径的警告 |
serial | 当在可序列化的类上缺少serialVersionUID定义时的警告 |
finally | 任何finally子句不能完成时的警告 |
all | 关于以上所有情况的警告 |
元注解
修饰其他注解的注解叫做元注解。
- @Target
使用@Target可以定义Annotation能够被应用于源码的哪些位置:
修饰范围 | 取值 |
---|---|
类或接口 | ElementType.TYPE |
字段 | ElementType.FIELD |
方法 | ElementType.METHOD |
构造方法 | ElementType.CONSTRUCTOR |
方法参数 | ElementType.PARAMETER |
局部变量 | ElementType.LOCAL_VARIABLE |
包 | ElementType.PACKAGE |
@Target注解的源代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
其中 value() 是参数名,ElementType[ ]是参数类型,是一个数组,可有多个值。
即使用方式为
@Target(value=ElementType.METHOD)
或
@Target(value={ElementType.METHOD,ElementType.TYPE})
- @Retention
@Retention用来表示需要在什么级别保存该注释信息,用于描绘注解的生命周期。
取值RetentionPolicy | 作用 |
---|---|
SOURCE | 在源文件中有效(源文件保留注解) |
CLASS | 在class文件中有效(class保留) |
RUNTIME | 在运行时有效,此注解可以被反射机制读取 |
@Retention注解的源代码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
通常我们自定义的Annotation使用Retention修饰时,值都为RUNTIME。
- @Repeatable
使用@Repeatable这个元注解可以定义Annotation是否可重复,经过@Repeatable修饰后,在某个类型声明处,就可以添加多个此注解;此元注解应用不是很广泛。 - @Inherited
使用@Inherited定义子类是否可继承父类定义的Annotation。@Inherited仅针对@Target(ElementType.TYPE)类型的annotation有效,并且仅针对class的继承,对interface的继承无效。
自定义注解
- 第一步,用@interface定义注解;
- 第二步,添加参数、默认值。把最常用的参数定义为value(),推荐所有参数都尽量设置默认值。
- 第三步,用元注解配置注解。必须设置@Target来指定Annotation可以应用的范围;必须设置@Retention,属性值最好为RetentionPolicy.RUNTIME便于运行期读取该Annotation。
示例
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DxtAnnotation {
String value() default "";
int age() default 0;
int id() default -1; //默认设为-1
}
使用时
@DxtAnnotation(value="dxt", age=18, id=111, schools={"蓝翔", "新东方"})
public void test(){
}
使用时如果注解只有一个参数value()时,则可以直接在括号中添加值,比如:
@DxtAnnotation("dxt")
public void test(){
}
反射获取注解
- 有一个Student类,使用注解去修饰这个类和这个类中的属性。注解中的信息就是修饰对应数据的,我们可以通过获取对应注解,获取对应数据的更多信息。
- 注解定义中,@Retention的值必须设置为RetentionPolicy.RUNTIME,因为反射就是发生在程序运行中。
注解1(修饰类)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 为Student类自定义一个注解
* 为类指定一个数据库中的表名,存储到value中
* @author dxt
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value() default "";
}
注解2(修饰类中的属性)
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 为Student中的属性自定义一个注解
* 说明属性对应数据库表中的字段信息
* @author dxt
*
*/
@Target(value = ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {
String columnName(); //列名
String type(); //类型
int length(); //长度
}
Student类
/**
* student类
* @author dxt
*
*/
@Table(value = "tb_student")
public class Student {
@Field(columnName="id", type="int", length=10)
private int id;
@Field(columnName="sname", type="varchar", length=10)
private String name;
@Field(columnName="age", type="int", length=3)
private int age;
public Student(){
}
public Student(int id, String name, int age){
super();
this.id = id;
this.name = name;
this.age = age;
}
public void setId(int id){
this.id = id;
}
public int getId(){
return this.id;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return this.age;
}
}
反射获取注解
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
/**
* 使用反射机制读取注解的信息,模拟处理竹节信息的流程
* @author dxt
*
*/
public class Demo03 {
public static void main(String[] args){
try {
Class c = Class.forName("dxt.annotation.Student");
//获取类的所有注解
Annotation[] annos = c.getAnnotations();
for(Annotation a : annos){
System.out.println(a);
}
//依据注解类,直接获取指定注解
Table table = (Table)c.getAnnotation(Table.class);
System.out.println(table.value());
//获取类的属性的注解
Field f = c.getDeclaredField("name");
//教训:怎么可以把类名设置为 Field呢
dxt.annotation.Field fa = f.getAnnotation(dxt.annotation.Field.class);
System.out.println(fa.columnName()+"--"+fa.type()+"--"+fa.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}