定义
- 注解,亦叫做注释,英文单词:Annotation
- 注解Annotation是一种引用数据类型,编译之后也是生成xxx.class文件
- 怎么样自定义注解?语法格式是啥?
[ 修饰符列表 ] @interface 注解类型名{ }
- 使用注解的语法格式:
@注解类型名
- 注解用在什么地方法
- 注解可以用在类上、属性上、方法上、变量上…
- 注解甚至能出现在注解类型上
注解类
public @interface MyAnnotation {
}
注解使用的位置
package Day19注解;
public class Test01 {
@MyAnnotation //属性
private int no;
@MyAnnotation //构造方法
public Test01() {}
@MyAnnotation //静态方法
public static void doSome(){}
@MyAnnotation //实例方法
public void doOther(){
@MyAnnotation //局部变量
int i = 1;
}
public void m1(@MyAnnotation String name){} //形参
}
@MyAnnotation //接口
interface MyInterface{}
@MyAnnotation //枚举
enum Season{
SPRING,SUNMER,AUTUMN,WINTER
}
和
package Day19注解;
@MyAnnotation //其他注释
public @interface OtherAnnotation {
}
综上所述:注释能出现在:属性、构造方法、静态方法、实例方法、局部变量、接口、枚举类型、其他注释上
Override注解
注解类型 | 描述 |
---|---|
Deprecated | 一个程序单元注释”不是一个程序员应该使用,通常是因为它是危险的,因为一个更好的选择的存在。 |
Override | 表示一个方法声明的目的是覆盖父类方法声明。 |
SuppressWarnings | 指示在注释元素(和包含在注释元素中的所有程序元素中)应被抑制命名的编译器警告。 |
Override注解
package Day19注解;
public class Test02 {
/*
Override的源码:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}
* */
@Override
public String toString() {
return "toString";
}
}
解释:
@Override这个注解只能注解方法
该注解是给编译器参考的,和运行阶段没有关系,如果java中的方法带有这个注解,编译器就会进行编译检查,如果该方法没有重写父类的方法,则报错
元注解
- 定义:标注“注解类型”的注解
- 常见的元注解
- Target
- Retention
- Target
- 这是一个元注解,用来标注“注解类型”的注解
- 作用:限制被标注的注解出现的位置
- 实例
@Target(ElementType.METHOD)
//表示被该注解标注的注解只能出现在方法上
- Retention
- 标注“被标注的注解”最终保存在哪里
- 实例
@Retention(RetentionPolicy.SOURCE)
//表示该注解只是被保留在Java源文件中
@Retention(RetentionPolicy.CLASS)
//表示该注解被保存在class文件中
@Retention(RetentionPolicy.RUNTIME)
//表示该注解被保存在class文件中,并且可以被反射机制所读取
Deprecated注解
作用:告诉其他人这个东西已经过时了,目前已经有了更好的解决方案
package Day19注解;
@Deprecated
public class Test03 {
public static void main(String[] args) {
Test03 test03 = new Test03();
test03.doSome();
}
@Deprecated
public static void doSome(){
System.out.println("do Something...");
}
public static void doOther(){
System.out.println("do Other thing...");
}
}
class Test04{
public static void main(String[] args) {
Test03 test03 = new Test03();
test03.doOther();
try {
Class<?> aClass = Class.forName("Day19注解.Test03");
Object object = aClass.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wC73NyzH-1612032291499)(en-resource://database/708:1)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s2ZWQoiH-1612032291501)(en-resource://database/710:1)]
表示该方法和该类均被淘汰了
注解定义属性
自定义属性
package Day19注解;
public @interface MyAnnotation {
String name();
String color();
int age = 21; //属性指定默认值
}
测试
package Day19注解;
public class Test05 {
// @YourAnnotation()
// public void doSome(){}
// 对于元素name,color, 注释 @Day19注解.YourAnnotation 缺少默认值
@YourAnnotation(name = "张三", color = "black")
public void doSome(){}
public static void main(String[] args) {}
}
注意事项:
- 在注解中也是可以定义属性的
- 虽然属性后面有个小括号,看着很像是方法,但是这实际上就是注释的属性
- 如果注解中有属性,则必须给属性赋值,除非本身就使用default指定了默认值
属性是value的时候
当注解仅有一个value属性的时候:
注解类:
package Day19注解;
public @interface YourAnnotation2 {
String value();
}
测试:
package Day19注解;
public class Test06 {
@YourAnnotation2(value = "张三")
public void doSome(){}
@YourAnnotation2("李四")
public void doOther(){}
public static void main(String[] args) {}
}
注意事项:
当注释中仅有一个属性,且该属性的名字是value的时候,在调用该注释的时候,小括号中的“value = ”可以直接省略
当注释不仅仅有一个value属性的时候
注解类:
package Day19注解;
public @interface YourAnnotation3 {
String value();
String name();
}
测试:
package Day19注解;
public class Test07 {
@YourAnnotation3(value = "李四", name = "张三")
public void doSome(){}
public static void main(String[] args) {}
}
注意事项:
当先将“value = ”省略的时候,去填name,IDEA会自动的将“value = ”加上,如果没有,则会报错
属性是一个数组
- 注解的属性类型可以是:byte short int long float double boolean char String Class 枚举类型
package Day19注解;
public @interface MyAnnotation2 {
int value1();
String value2();
int[] value3();
String value4();
Season value5();
Season[] value6();
Class parameterType();
Class[] parameterTypes();
}
枚举:
package Day19注解;
public enum Season2 {
SPRING,SUMMER,AUTUMN,WINTER
}
属性为枚举类型:
package Day19注解;
public @interface MyAnnotation3 {
int age();
String[] name();
Season[] seasonArray();
}
测试:
package Day19注解;
public class Test08 {
@MyAnnotation3(age = 21, name = {"张三", "李四"}, seasonArray = {Season.AUTUMN,Season.SPRING})
public void doSome(){}
@MyAnnotation3(age = 21, name = "张三", seasonArray = {Season.AUTUMN,Season.SPRING})
public void doOther(){}
}
注意事项:
- 枚举类型的属性写入的时候,需要加枚举类型的名字
- 如果数组只有1个元素,大括号是可以省略的
反射注解
自定义注解:
package Day19注解;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//该注解只能标记类和方法
@Target({ElementType.TYPE,ElementType.METHOD})
//该注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation4 {
String value() default "广东广州";
}
测试注解:
package Day19注解;
@MyAnnotation4("四川成都")
public class Test09 {
// @MyAnnotation4("四川成都") //因为Target标注限制,所以MA4注释不能注释属性
int i;
// @MyAnnotation4("四川成都") //因为Target标注限制,所以MA4注释不能注释构造方法
public Test09(){}
@MyAnnotation4("四川成都")
public void doSome(){
// @MyAnnotation4("四川成都") //因为Target标注限制,所以MA4注释不能注释局部变量
int i;
System.out.println("doSome...");
}
}
通过反射获取类的注释
package Day19注解;
public class Test10 {
public static void main(String[] args) throws ClassNotFoundException {
//获取类
Class<?> t9Class = Class.forName("Day19注解.Test09");
//判断该类上是否存在MyAnnotation4注释
if (t9Class.isAnnotationPresent(MyAnnotation4.class)){
//获取该注释对象
MyAnnotation4 t9ClassAnnotation = t9Class.getAnnotation(MyAnnotation4.class);
//输出该注释对象
System.out.println(t9ClassAnnotation);
//获取注释对象的属性值
String value = t9ClassAnnotation.value();
//输出属性
System.out.println(value);
}
//对比实验,判断String类上面有无@MyAnnotation4
//获取类
Class<?> aClass = Class.forName("java.lang.String");
if (aClass.isAnnotationPresent(MyAnnotation4.class)){
System.out.println(aClass.getAnnotation(MyAnnotation4.class));
} else {
System.out.println(aClass.getSimpleName() + "类型不存在MyAnnotation4注释");
}
}
}
注意事项:
- 是判断某个java文件是否存在某种类型的注释,所以获取的是该java文件的类,而不是该注释的类
- 获取到后就需要进行判断是否存在该注释,使用isAnnotationPresent()方法
通过反射获取注解对象的值
自定义注解:
package Day19注解;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation5 {
String name();
String id();
}
测试:
package Day19注解;
//获取本类doSome()方法上面的注释信息
import java.lang.reflect.Method;
public class Test11 {
@MyAnnotation5(name = "张三", id = "001")
public void doSome(){}
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
//获取本类
Class<?> t11Class = Class.forName("Day19注解.Test11");
//获取doSome()方法
Method dsMethod = t11Class.getMethod("doSome");
//判断doSome()方法是否存在注解
if (dsMethod.isAnnotationPresent(MyAnnotation5.class)){
//获取该注释对象
MyAnnotation5 dsMethodAnnotation = dsMethod.getAnnotation(MyAnnotation5.class);
System.out.println("用户的名字是:" + dsMethodAnnotation.name() + ",id是:" + dsMethodAnnotation.id());
} else {
System.out.println(t11Class.getSimpleName() + "的" + dsMethod.getName() + "没有MyAnnotation5的注释");
}
//对比试验,判断Test09类中的doSome()方法有无@MyAnnotation5注释
Class<?> aClass = Class.forName("Day19注解.Test09");
Method doSome = aClass.getMethod("doSome");
if (doSome.isAnnotationPresent(MyAnnotation5.class)){
MyAnnotation5 annotation = doSome.getAnnotation(MyAnnotation5.class);
System.out.println("用户的名字是:" + annotation.name() + ",id是:" + annotation.id());
} else {
System.out.println(aClass.getSimpleName() + "的" + doSome.getName() + "没有MyAnnotation5的注释");
}
}
}