1. 注解的写法
public @interface MyAnnotation {
int STATUS=0;
int age();
String name();
}
关注点
- 在interface前面加个@,来声明这是一个注解
- 注解中的第一行代码,是一个常量,并且注解和接口一样,声明的常量默认也只能是public final类型的
- 注解的第二三行代码,分别是一个int型和String型的变量,并且注解中不支持定义方法
在用该注解的时候,需要给注解中的变量赋值
@MyAnnotation(age=18,name="张三")
如果注解中只有一个变量,可以命名为value
此时赋值的时候,可以这样
public @interface MyAnnotation {
int STATUS=0;
String value();
}
@MyAnnotation("张三")
注解中的变量可以设置默认值,这样在用注解的时候,就不用给变量赋值,也可以编译通过了
public @interface MyAnnotation {
String name() default "张三";
}
@MyAnnotation()
2. 元注解
注解上的注解就是元注解,并且元注解只能用在注解上,Java提供了4中元注解
@Target
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
ElementType是一个枚举类
- ElementType.TYPE:修饰类、接口或枚举(enum)
- ElementType.FIELD:注解成员变量
- ElementType.METHOD:注解方法
- ElementType.PARAMETER:注解方法参数
- ElementType.CONSTRUCTOR:注解构造函数
- ElementType.LOCAL_VARIABLE :注解局部变量
- ElementType.ANNOTATION_TYPE 注解另一个自定义注解
- ElementType.PACKAGE 注解包
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
RetentionPolicy是一个枚举类
- RetentionPolicy.SOURCE:在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码
- RetentionPolicy.CLASS:默认值(自定义注解默认是RetentionPolicy.CLASS),编译器仅把注解保存在class文件中,在运行java程序时,JVM不会保留注释,即不能用反射(在运行期)来获取注释
- RetentionPolicy.RUNTIME:编译器不仅把注解保存在class文件中,同时在运行java程序时,JVM也会保留注释,即可以通过反射来获取注释
android从源码到apk文件的大体流程
Java源码——>class文件——>dex文件——>apk
SOURCE对应Java源码到class文件,CLASS对应class文件到apk,RUNTIME则对应app运行期间
@Documented
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
作用
将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同
@Inherited
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
作用
使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。
3. Java自带注解
@Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
该注解的作用在于声明该方法是覆盖的父类的方法
来段代码
public interface Readable {
boolean canRead();
}
public class English implements Readable{
@Override
public boolean canRead() {
return false;
}
public String getName(){
return "English";
}
public static void main(String[] args){
System.out.println("测试注解@Override");
}
}
当我们去掉canRead方法上的注解,编译器不会报错,程序也能正常运行
但是当我们在getName方法上加注解时,编译器会报错,程序运行也会报错
则得出的结论是
@Override就是一个标注,被标注的方法在子类中一定存在相同的方法,因为拼写错误时,子类没有此方法,则编译器会报错
@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
用于表明类(class)、方法(method)、字段(field)已经不再推荐使用,并且在以后的JDK版本中可能将其删除,编译器在默认情况下检测到有此标记的时候会提示警告信息。
@SuppressWarnings
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
作用在于告诉编译器忽略某个警告信息
如@SuppressWarnings("deprecation")则会告诉编译器,不要在输出关于过时的警告信息
4. 注解的作用
前面讲了这么多,总结起来就一句话,注解其实就是一个标记,通过读取注解中的不同标记,编译器或程序会做出相应的事情
如上面的@SuppressWarnings("deprecation"),当编译器读取到这个标记时,则不会再输出关于过时的警告信息了
自定义注解标记的获取
@MyAnnotation(name = "我是Main类")
public class Main {
@MyAnnotation(name = "我是main方法")
public static void main(String[] args) throws NoSuchMethodException {
Class c1=Main.class;
MyAnnotation annotation1= (MyAnnotation) c1.getAnnotation(MyAnnotation.class);
System.out.println(annotation1.name());
Method method=c1.getMethod("main",String[].class);
MyAnnotation annotation2=method.getAnnotation(MyAnnotation.class);
System.out.println(annotation2.name());
}
}
自定义注解,我们一般通过反射,来获取注解的信息,得到信息之后,可以根据不同的信息作出不同的操作即可
注解用反射获取注解信息,要求注解的必须为运行时注解
@Retention(RetentionPolicy.RUNTIME)
否则通过上述反射获取到的注解对象为null
5. 安卓中常见的注解
@NonNull和@Nullable
这两个注解是用来标注方法是否能传入null值,如果可以传入null值,则标记为Nullable,如果不可以则标注为NonNull。在我们做了一些不安全严谨的编码操作的时候,这些注释会给我们一些警告(程序编译和运行都不会报错)。比如说
@SuppressLint
指示Lint应忽略带注释元素的指定警告
@Parcel
与implements Parcelable作用相同,免去手写Parcelable相关的代码
@UiThread和@WorkThread
指定方法工作在主线程/子线程