注解:Annotation,也是一种引用数据类型。编译之后生成class文件。
语法:
[修饰符列表] @interface 注解名{
属性(可有可无)
}
IDEAZ中可直接生成Annotation:
package com.dh.annotation;
public @interface MyAnnotation {
}
注解可用在类、接口、属性、方法、变量,(也包括注解)等等位置上:
package com.dh.annotation;
@MyAnnotation
public class User {
@MyAnnotation
private int age;
@MyAnnotation
public User(@MyAnnotation int age) {
this.age = age;
}
@MyAnnotation
public void show() {
@MyAnnotation
String s = "abc";
System.out.println(s);
}
}
注解的作用其实就是一个标识作用:即有注解怎么样,没有注解怎么样。
JDK内置注解
在java.lang包下有三个注解:
- @Deprecated:表示过时。
- @Overried:出现在方法上,给编译器参考,于运行阶段没有关系。编译器会编译检查该方法是否是重写父类的方法,如果不是会有红色波浪线编译错误。
- @SuppressWarning(不常用)
@Deprecated
使用:
public class User {
@Deprecated
public int age;
}
*效果:使用user类的age属性时,会出现删除线,并且允许会有warnning。
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {
String since() default "";
boolean forRemoval() default false;
}
@Overried
使用:
package com.dh.annotation;
public class Test {
@Override
public String toString() {
return "重写toString方法";
}
}
//若不是重写父类的方法会直接编译报错(在此处就不放图片了,可以自行测试)
源码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
可以看到Override注解中没有任何的内容,但是其上面又有两个注解。
注解注解的注解叫元注解(中国文化博大精深!),即@Target和@Retention在此处为元注解。
@Target
用来指定注解可以放的位置。ElementType.METHOD代表只能放在方法上。
点开Target的源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value(); //ElementType为一个枚举类型
}
//ElementType的属性:(各个属性的意思可以查看api文档)
//TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE,MODULE
@Retention
用来指定注解保存的位置。RetentionPolicy.SOURCE表示保存在java源文件中。
点开Retention的源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value(); // RetentionPolicy是一个枚举类型
}
//RetentionPolicy的属性:(各个属性的意思可以查看api文档)
//SOURCE,CLASS,RUNTIME
注解属性
上面的注解都有自己的属性。那注解如何书写自己的属性呢?
语法:
类型 属性名()[default 值];//[]可选
//类型可以是8大基本数据类型、String、Class、枚举,及它们的数组。(其余就不行了)
- 如果注解中有属性,在使用时需要给它们赋值,否则会报错,除非有默认值,有默认值再赋值则会覆盖掉默认值。
格式:@注解(name = value,...,(数组)name = {value1,...}(如果数组中只有一个值,可以省略{})。
- 如果注解中的属性名是value,并且只有一个,value =可以省略不写,只写属性值。
例:
枚举类:
package com.dh.annotation;
public enum DAY {
ONE,TWO,THREE,FOUR,FIVE,SIX,SEVEN
}
注解类:
package com.dh.annotation;
@Target(ElementType.FIELD) //只能用于属性上
@Retention(RetentionPolicy.RUNTIME) //保存到类文件上,并由JVM运行时保存,可以被反射获取到
public @interface MyAnnotation {
String name();
int age();
//有默认值
double grade() default 100;
//枚举数组
DAY[] day();
}
测试类:
package com.dh.annotation;
public class User {
@MyAnnotation(name = "Tom",age = 18,day = {DAY.FIVE,DAY.SEVEN})
private int age;
}
利用反射获取注解的属性及属性值
注解类:
package com.dh.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name();
int age();
//有默认值
double grade() default 100;
//枚举数组
DAY[] day();
}
User:
package com.dh.annotation;
public class User {
@MyAnnotation(name = "Tom",age = 18,day = {DAY.FIVE,DAY.SEVEN})
@Deprecated
public int age;
}
测试:
package com.dh.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
public class Test {
//为了代码更好看,将异常采取throws方式处理
public static void main(String[] args) throws Exception {
//先获取Class对象
Class c = Class.forName("com.dh.annotation.User");
//出现在属性上的注解,要先获取属性
Field age = c.getDeclaredField("age");
boolean b = age.isAnnotationPresent(MyAnnotation.class);
System.out.println(b);
if(b){
//获取注解
Annotation[] annotations = age.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
}
结果:
true
@com.dh.annotation.MyAnnotation(grade=100.0, name="Tom", age=18, day={FIVE, SEVEN})
@java.lang.Deprecated(forRemoval=false, since="")
总结一下,其实也就需要掌握四个常用注解的注解功能,以及如何自定义注解,自定义注解中如何定义属性(可以支持的属性数据类型有哪些),注解可以用在哪里,具体如何使用注解(包括属性的使用)。