一、入门注解的应用
经常会遇到这样的情况
package Tokyo.Hot;
public class Demo {
public static void main(String[] args) {
new Thread().stop();
//画一条线,很明显是过时的方法
}
}
这是过时的方法,这时就要用到注解,告诉编译器,我知道这是过时的,我就喜欢用
@SuppressWarnings("deprecation") deprecation,过时的,背单词
package Tokyo.Hot;
public class Demo {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
new Thread().stop();
}
}
注意:一个注解就是一个类
当你以前写好了一个类的方法,但是现在不想用了,为了不给用这个方法的人造成困扰,那么就可以在方法上添加一个@Deprecated,这是
一个过时的方法
public class Demo {
public static void main(String[] args) {
Out();
}
@Deprecated
private static void Out() {
System.out.println("Hello,World!");
}
}
HashSet,需要复写equals方法,但是equals(),参数是Object类型,但是一不小心,写成别的类,这个错误很不容易找到,那么这时,就需要用到注解@Override,复写
new Thread(new Runnable() {
@Override
public int run() {
}}).start();
注解,相当于一种标记,在包、类、方法、变量、字段等上面添加了这种标记,告诉编译器,你按照我的标记采取相应的动作
OK,注解的皮毛,已然了解!
二、注解的定义和反射调用
我们想使用某个类,那么就必须先设计写好那个类,注解也是如此,我们想使用某个注解,那么我们也必须提前先设计写好那个注解
1.定义注解类:
public @interface MyTokyo {} 和定义接口的方式是一样的
2.应用了注解的类:
@MyTokyo
class MyClass{},检查这个类上是否有这个注解
3.对"应用注解的类"进行反射
要对一个类进行检查,肯定用到反射
@MyTokyo
public class Demo {
public static void main(String[] args) {
Boolean flag = Demo.class.isAnnotationPresent(MyTokyo.class);//检查是否有注解
if(flag){
MyTokyo myTokyo = (MyTokyo) Demo.class.getAnnotation(MyTokyo.class);//得到这个注解对象
System.out.println(myTokyo);
}
}
}
会发现什么也不打印
在自定义的注解上添加注解,注解的注解->源注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTokyo {}
@Retention(RetentionPolicy.RUNTIME)的意义,也就是告诉编译器,将自定义的注解保留到运行期,因为自定义的注解可能在编译期,就清除了,javac把源文件编译成class,可能就把源程序的注解就去掉了,还有可能是在类加载器把类加载到内存时,类中的注解是否保留,
也是问题。
特别注意:class文件中的东西,不是字节码,只有类加载器把class文件进行安全检查等一系列的处理后,加载到内存的二进制才是字节码
一个注解的生命周期有三个阶段:
1.java源文件 2.class文件 3.内存中的字节码
所以@Retention就有三种取值:
(RetentionPolicy.SOURCE 源文件阶段)
(RetentionPolicy.CLASS class文件阶段)
(RetentionPolicy.RUNTIME 运行阶段)
而默认值是CLASS阶段
@Override的默认值是(RetentionPolicy.SOURCE 源文件阶段)
@SuppressWarnings的默认值是(RetentionPolicy.SOURCE 源文件阶段)
@Deprecated的默认值 (RetentionPolicy.RUNTIME 运行阶段)
继续,在自动注解上再加一个注解@Target
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface MyTokyo {}
作用:告诉编译器,自定义的注解只能加载方法上
要想使注解在类和方法都能使用
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyTokyo {}
注意是TYPE,类型,不仅仅是class,接口都可以,所以用TYPE更贴切,而不用class
三、为注解增加属性
注解之所以强大,是因为其的属性
注解很像接口,而注解的属性就很像方法
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyTokyo {
String color();//注解有个属性color,返回字符串
}
那么主函数就可以是设置属性值
@MyTokyo(color="red")
public class Demo {
public static void main(String[] args) {
Boolean flag = Demo.class.isAnnotationPresent(MyTokyo.class);//检查是否有注解
if(flag){
MyTokyo myTokyo = (MyTokyo) Demo.class.getAnnotation(MyTokyo.class);//得到这个注解对象
System.out.println(myTokyo.color());
}
}
}
打印red,这就是为注解添加属性,在用的时候,给它设置属性值
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyTokyo {
String color() default "blue";//默认是blue
String value();
}
@MyTokyo(color="red",value="ax")//属性没有设置默认的时候,所有属性必须都要写
public class Demo {
@MyTokyo("xc")//因为color设置了缺省值,所以可以只写xc代表value的属性值,可以不写value
public static void main(String[] args) {
Boolean flag = Demo.class.isAnnotationPresent(MyTokyo.class);//检查是否有注解
if(flag){
MyTokyo myTokyo = (MyTokyo) Demo.class.getAnnotation(MyTokyo.class);//得到这个注解对象
System.out.println(myTokyo.color());
}
}
}
数组类型的属性
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyTokyo {
String color() default "blue";
String value();
int[] arr() default {3,4,5};
}
注意数组的元素如果只有一个的话,arr=1,可以不写大括号
@MyTokyo(color="red",value="ax",arr={1,2,3,4})
public class Demo {
@MyTokyo("xc")
public static void main(String[] args) {
Boolean flag = Demo.class.isAnnotationPresent(MyTokyo.class);
if(flag){
MyTokyo myTokyo = (MyTokyo) Demo.class.getAnnotation(MyTokyo.class);//得到这个注解对象
System.out.println(myTokyo.color());
System.out.println(myTokyo.value());
System.out.println(myTokyo.arr().length);
}
}
}
枚举类型的属性
//定义一个枚举类
public class Week {
private Week(){}
public final static Week SUN = new Week();
public final static Week MON = new Week();
public Week nextDay(){
return this==SUN? MON : null;
}
public String toString(){
return this==MON ? "MON":"SUN";
}
public enum WeekDay{
SUN,MON;
}
}
定义枚举类型的属性
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyTokyo {
String color() default "blue";
String value();
Week.WeekDay Day() default Week.WeekDay.SUN;//定义枚举类型的属性
int[] arr() default {3,4,5};
MyAnotaion2 anotaionArr() default @MyAnotaion2("x");
}
@MyTokyo(anotaionArr=@MyAnotaion2("wjw"),color="red",value="ax",arr={1,2,3,4})
public class Demo {
@MyTokyo(value="xc",Day=Week.WeekDay.SUN)
public static void main(String[] args) {
Boolean flag = Demo.class.isAnnotationPresent(MyTokyo.class);
if(flag){
MyTokyo myTokyo = (MyTokyo) Demo.class.getAnnotation(MyTokyo.class);//得到这个注解对象
System.out.println(myTokyo.Day().name());
}
}
}
注解类型的属性
public @interface MyAnotaion2 {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyTokyo {
String color() default "blue";
String value();
int[] arr() default {3,4,5};
MyAnotaion2 anotaionArr() default @MyAnotaion2("x");//返回一个MyAnotaion2注解的注解类型属性
}
注解中的注解类型属性
@MyTokyo(anotaionArr=@MyAnotaion2("wjw"),color="red",value="ax",arr={1,2,3,4})
public class Demo {
@MyTokyo("xc")
public static void main(String[] args) {
Boolean flag = Demo.class.isAnnotationPresent(MyTokyo.class);
if(flag){
MyTokyo myTokyo = (MyTokyo) Demo.class.getAnnotation(MyTokyo.class);//得到这个注解对象
System.out.println(myTokyo.color());
System.out.println(myTokyo.value());
System.out.println(myTokyo.arr().length);
System.out.println(myTokyo.anotaionArr().value());
}
}
}
注解的属性返回值还可以是8个基本类型、class、刚才所有类型的数组
通过看文档可以更好的了解注解,注解的应用已经越来越广泛,以后要注意此方面的应用