注解(Annotation)
1. 基本概念
-
注解Annotation是一种引用数据类型,编译之后也是生成xxx.class文件
-
自定义注解的语法格式:
[修饰符列表] @interface 注解类型名{ }
/* 自定义注解 */ public @interface MyAnnotation { }
-
使用方式
-
注解使用时的语法格式
@注解类型名
-
注解可以出现在类上、属性上、方法上、变量上等,还可以出现在注解类型上
-
2. JDK常用内置注解
java.lang包下的注释类型
- Deprecated:用@Deprecated注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择
- Override:便是一个方法声明打算重写超类中的另一个方法声明
(1)Deprecated
Deprecated这个注解标注的元素已过时,有更好的解决方案
(2)Override
源代码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
- Override这个注解只能注解方法(原因见下一小结)
- 这个注解是给编译器参考的,和运行阶段没有关系。凡是java中的方法带有这个注解,编译器都会进行编译检查,如果这个方法不是重写父类的方法,编译器会报错
3. 元注解
-
用来标注“注解类型”的“注解”,称为元注解
-
常见的元注解:Target和Retention
-
Target注解
Target注解用来标注“被标注的注解”可以出现在哪些位置上
@Target(ElementType.METHOD):表示“被标注的注解”只能出现在方法上(Override只能注解方法的 原因) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE}):表示该注解能出现在构造方法上、字段上、局部变量上、方法上、包上、参数上、类上
-
Retention注解
Retention注解用来标注“被标注的注解”最终保存在哪里
@Retention(RetentionPolicy.SOURCE):表示该注解只被保存在java源文件中 @Retention(RetentionPolicy.CLASS):表示该注解被保存在class文件中 @Retention(RetentionPolicy.RUNTIME):表示改锥姐被保存在class文件中,并且可以被反射机制 读取
-
4. 自定义注解
示例:
/*
自定义注解
*/
public @interface MyAnnotation {
/**
* 我们通常在注解当中可以定义属性,以下这个是MyAnnotation的name属性。
* 看着像是一个方法,但实际上我们称之为属性name
* @return
*/
String name();
}
Test类调用
public class Test {
public static void main(String[] args) {
}
//MyAnnotation(属性名 = 属性值,属性名 = 属性值,...)
@MyAnnotation(name = "lisi")
public void doSome(){
}
}
如果一个注解当中有属性,那么必须给属性赋值,除非该属性使用default指定了默认值
5. 注解属性
(1)注解属性的类型
注解当中的属性类型可以是byte, short, int, long, float, double, boolean, char, String, Class, 枚举类型以及以上每一种的数组形式
MyAnnotation
/*
自定义注解
*/
public @interface MyAnnotation {
/**
*
* @return
*/
int age();
String[] email();
Season[] season();
}
枚举Season
public enum Season {
SPRING, SUMMARY, AUTUMN, WINTER
}
Test
public class Test {
public static void main(String[] args) {
}
@MyAnnotation(age = 123,email = {"123@qq.com","123@163.com"},season = {Season.AUTUMN,Season.SPRING})
public void doSome(){
}
//如果数组中只有一个元素,大括号可以省略
@MyAnnotation(age = 321, email = "123@qq.com",season = Season.AUTUMN)
public void doOther(){
}
}
(2)value的特殊性
如果一个注解的属性名为value,那么在调用这个注解时,可以将属性名省略,直接写属性值
MyAnnotation
public @interface MyAnnotation {
/**
*
* @return
*/
String value();
}
Test
public class Test {
public static void main(String[] args) {
}
@MyAnnotation("lisi")
public void doSome(){
}
}
属性名必须是value的时候,才可以这么写,其他属性名不可以!并且只能含有唯一一个属性就是value
6. 反射机制获取类上面的注解及属性
MyAnnotation
/*
自定义注解
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "zhangsan";
}
Student类
@MyAnnotation
public class Student {
}
Test类
public class Test {
public static void main(String[] args) throws Exception {
//获取这个类
Class studentClass = Class.forName("com.study.www.annotation.Student");
//判断类上面是否有@MyAnnotation
if(studentClass.isAnnotationPresent(MyAnnotation.class)){
//获取该类的注解对象
MyAnnotation myAnnotation = (MyAnnotation)studentClass.getAnnotation(MyAnnotation.class);
System.out.println("类上面的注解对象为:"+myAnnotation);
//获取注解对象的属性
String value = myAnnotation.value();
System.out.println(value);//zhangsan
}
}
}
注:只有在注解中的元注解Retention的属性值为RUNNTIME时,才可以通过反射机制获取,否则会出现异常
7. 反射机制获取方法上的注解以属性
MyAnnotation
/*
自定义注解
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String username();
String password();
}
Student类
public class Student {
@MyAnnotation(username = "admin", password = "123456")
public void doSome(){
}
}
Test类
public class Test {
public static void main(String[] args) throws Exception {
//获取这个类
Class studentClass = Class.forName("com.study.www.annotation.Student");
//获取doSome()方法
Method doSomeMethod = studentClass.getDeclaredMethod("doSome");
//判断方法上面时候有注解
if(doSomeMethod.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation myAnnotation = doSomeMethod.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation.username());//admin
System.out.println(myAnnotation.password());//123456
}
}
}