一、注解基本语法
(1)定义
interface关键字前面有一个@,它告诉编译器此处声明了一个注解
因为注解都自动继承了java.lang.annotation.Annotation接口,所以,不能在extends其他类
注解可以用在类,方法、变量、形式参数、enum等
public @interface AnnoTest{
public String name();
}
(2)注解的属性
也叫做成员变量,注解只有成员变量,没有方法,注解的成员变量在注解的定义中以"无参数的方法"的形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
public @interface AnnoTest{
//特殊属性名
public string value();
//看着像方法,name是属性的名字,String是返回类型
public String attr();
//default属性默认值
public String attr2() default "abc";
//一维数组的属性
public String[] attr3();
}
- 属性类型为八种基本数据类型 (byte,short,char,int,long,float,double,boolean,String,Enum,Class,annotations)以及这些类型的一维数组
- 如果属性没有默认值,则必须为其赋值,有默认值可以重新为其赋值
- 标记注解:不包含成员的注解叫做标记注解
- 单成员注解:包含一个成员的注解,成员名建议写成value,当成员名是value,给其赋值时,可以省略value=(这里必须是但成员注解)
(3)注解使用
@AnnoTest(value="value",attr1="name",attr3={"a","b"})
public class Test{
}
二、java预置注解
java预置的注解有@Deprecated,@Override,@SuppressWarnings,@SafeVarargs,@FunctionalInterface
(1)@Deprecated 过时,编译器会警告提示,源码如下:
package java.lang;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
(2)@Override 子类覆写父类被@Override修饰的方法
package java.lang;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
(3)@SuppressWarnings 阻止警告,开发者忽略这种警告
package java.lang;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
* The string {@code "unchecked"} is used to suppress unchecked warnings*
String[] value();
}
//使用
public class ListText{
@SuppressWarnings(value="unchecked")
public void add()
}
(4)SafeVarargs 参数安全类型注解,提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生unChedked这样的警告,java1.7版本加入
package java.lang;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}
(5)@FunctionalInterface 函数式接口注解,java1.8加入
函数式接口就是一个具有一个方法的普通接口,如Runnable,函数式接口很容易转换成Lambda表达式。
package java.lang;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
三、元注解
元注解是一种基本注解,可以注解到注解上的注解,能够应用到其他的注解上面。元注解有五种:
@Documented,@Retention,@Target,@Inherited,@Repeatable
(1)@Documented
这个注解和文档有关,将注解中的元素包含到javadoc中去。
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
(2)@Retention (保留策略)
- RetentionPolicy.SOURCE 在源文件中有效,在编译器进行编译时它被丢弃忽视,起到提醒开发人员的作用,如:@override,APT技术
在APT技术中
// 获取所有被 @ARouter 注解的 元素集合
Set<? extends Element> elements = roundEnvironment.getElementsAnnotatedWith(ARouter.class);
//获取注解的值
ThorAnno annotation = element.getAnnotation(ThorAnno.class);
String value = annotation.value();
- RetentionPolicy.CLASS 在编译class文件有效,被虚拟机丢弃,不能加载到JVM中,如butterknife,arouter,eventbus,只要引入jar时有annotationProcessor 关键词的,一般都有这个注解 如:字节码加强
- RetentionPolicy.RUNTIME 程序运行时有效,会被加载到JVM中 如:注解+反射
//反射通过字节码获取
Class<?> clazz = this.getClass();
ThorAnno annotation = clazz.getAnnotation(ThorAnno.class);
if(annotation !=null){
annotation.value();
}
(3)@Target
注解运用的地方,限定运用的场景,共8种。
- ElementType.ANNOTATION_TYPE 对一个注解进行注解
- ElementType.CONSTRUCTOR 对构造方法注解
- ElementType.FIELD 对属性进行注解
- ElementType.LOCAL_VARIBLE 对局部变量进行注解
- ElementType.METHOD 对方法注解
- ElementType.PACKAGE 对包进行注解
- ElementType.PARAMETER 对一个方法内的参数进行注解
- ElementType.Type 对一个类型进行注解,如类,接口,枚举
(4)@Inherited
一个注解被@Inherited注解了,然后这个注解又注解了一个超类,如果这个超类的子类没有任何注解的话,那么子类就继承了超类的注解。
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
(5)Repeatable
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
/**
* Indicates the <em>containing annotation type</em> for the
* repeatable annotation type.
* @return the containing annotation type
*/
Class<? extends Annotation> value();
}
四、Android support annotation
(1)Nullness注解
用在参数或者返回值上,编译阶段注解
- @NonNull--- 不能为空
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface NonNull {
}
- @Nullable---可以为空
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {
}
(2)ResourceType 注解 一般用在参数为int的id资源
- @StringRes 字符串id资源注解
- @XmlRes xml文件id资源注解
- @ColorRes
- @AnimRes
- @DimenRes
- @IdRes
- @LayoutRes
/**
* 得到当前界面的资源文件Id
*
* @return
*/
@LayoutRes
protected abstract int getContentLayoutId();
(3)Threading 注解
- @WorkThread 工作线程
(4)overriding Methods注解
- @CallSuper
五、注解的提取
当注解的保留策略是RetentionPolicy.RUNTIME时,程序在运行时可以通过反射来查询注解信息
(1)类上的注解提取
通过Claas对象的isAnnotationPresent()方法判断这个类是否应用了某个注解,
public boolean inANnotationPresent(Class<? extends ANnotation> annotationClass)
如果被注解了,通过getAnnotation()或者getAnnotations()获取Annation对象
//获取指定类型的注解
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
//获取所有的注解
public Annotation[] getAnnotations()
获取到Annotation对象后,获取注解的属性值。
(2)获取属性和方法上的注解
Field name = Test.class.getDeclaredField("name");
if(name!=null){
name.setAccessible(true);
//获取一个成员变量上的注解
Check check = a.getAnnotation(Check.class);
if(check!=null){
check.value();
}
}
Method testMethod = Test.class.getDeclaredMethod("testMethod");
if ( testMethod != null ) {
// 获取方法中的注解
Annotation[] ans = testMethod.getAnnotations();
for( int i = 0;i < ans.length;i++) {
System.out.println("method testMethod annotation:"+ans[i].annotationType().getSimpleName());
}
}
六、注解多态
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseAnno {
String value();
int type();
}
@BaseAnno(value = "a",type = 1)
public @interface ChildA {
String value();
}
@BaseAnno(value = "b",type = 2)
public @interface ChildB {
String value();
}