转载自 Java和Android中的注解
1.引言
从JDK1.5开始,引入了注解类Annotation,Annotation其实是一种接口,可以作用于类、方法、属性等等 ,它可以通过反射机制来访问annotation信息,获取所加上注解信息,做相应的操作。相当于给相关的作用对象打上“tag”,使用方便,作用广泛。
2.java.lang中的注解
在java.lang中,用到三种注解类,即常用到的Deprecated,Override和SuppressWarnings.
2.1 @Deprecated 过时
在使用Eclipse或AS编写程序过程中,有一些方法编写出来之后被画上了中划线,表示该方法已过时,建议使用新的一些方法代替。
如:viewPager.setOnPageChangeListener()方法在安卓API23中已过时,在源代码中的该方法上赫然多了一个注解@Deprecated,可使用addOnPageChangeListener()方法代替。
如果使用javac命令编译,会弹出:”注意:使用或覆盖了已过时的API“
2.2 @Override 复写
这是开发过程中最常遇到的注解了,表示复写父类中的方法。如果方法上有这条注解但没有重写父类方法,则会生成一条错误消息。这个注解有效地保证了方法一定会被复写。比如开发过程中,手动在子类中复写父类方法,只正确写出了方法名称,未写正确方法的参数,则相当于方法的重载,并不是复写。这种问题如果在功能上有错误产生,在检查过程中是很难找到的。使用@Override注解,有效地表明,此方法是复写父类的方法,不会产生手动的错误问题。
2.3 @SuppressWarnings 阻止警告
阻止了弹出的警告,比如屏蔽对上述过时的提示,可在调用setOnPageChangeListener()方法之上加上@SuppressWarnings("deprecation"),这样虽然在IDE中仍以中划线的形式表示,但如果使用javac命令就不再提示警告。
3.元注解
那么以上的注解类的源码又是什么样的呢,打开Override发现其代码如下
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
这里可以发现注解类的定义方法以及注解类上所加的注解——元注解。元注解有四个,位于java.lang.annotation包中:Documented,Inherited,Retention,Target
3.1@Target
表示注解作用的目标。
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
注解可以作用的目标由枚举类ElementType决定,可作用于类、方法、属性等,数组表示注解可以有多个作用域。
public enum ElementType { TYPE,// 类、接口、注解类型或枚举 FIELD, //属性 METHOD, //方法 PARAMETER,// 用于描述参数 CONSTRUCTOR,//构造方法 LOCAL_VARIABLE,//局部变量 ANNOTATION_TYPE,//注解类 PACKAGE //包 }
注解作用于类时,定义@Target(ElementType.TYPE),ElementType .TYPE表示类型,Class,Interface等都实现了java中的Type接口,因此ElementType.TYPE 表示注解作用于这些"类"(并不是单纯的Class类)
3.2@Retention
表示注解的作用时段
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
由此可见,Retention定义的是RetentionPolicy类型的数据,RetentionPolicy是一个枚举类型,包括SOURCE,CLASS,RUNTIME三个类型。表示注解保留的阶段。
SOURCE:表示注解只在源文件中保留
CLASS:表示注解保留到.class文件中
RUNTIME:表示注解一直保留到内存中,类加载器把.class文件加载到内存中产生的字节码中要保留注解信息。
可想而知,@Override仅在写代码时用到,其Retention中的值为RetentionPolicy.SOURCE,@SuppressWarnings也只是编译器使用的,保留到SOURCE阶段。而@Deprecated在内存中也需要保留,编译器需要得知方法是否过时,从加载到内存中的二进制文件中获取,因而要保留到RUNTIME阶段
3.3@Documented
3.4@Inherited
4.注解的参数
5.自定义注解
@Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Car{ String name() default ""; int number() default -1; }
@Car(name="好车",number=666) public class CarBMW(){ }
if(CarBMW.class.isAnnotationPresent(Car.class)){//判断CarBMW类是否有注解类Car Car carAnnotation=(Car)CarBMW.class.getAnnotation(Car.class);//获取注解实例对象 Log.v("Shawn",carAnnotation.name());//获取name参数的值 Log.v("Shawn",carAnnotation.number());//获取number参数的值 }
5.1 JAVA8中注解的补充
在JAVA8中,增加了TypeAnnotation,在 Java 8 之前的版本中,只能允许在声明式前使用 Annotation。而在 Java 8 版本中,Annotation 可以被用在任何使用 Type 的地方,例如:初始化对象时 (new),对象类型转化时。
//初始化对象时 String myString = new @NotNull String(); //对象类型转化时 myString = (@NonNull String) str;这点上有点类似Android中的注解使用。
而ElementType中增加了俩个值ElementType. T YPE_PARAMETER 和ElementType. TYPE_USE 正是为此功能实现而产生的。
ElementType. TYPE_PARAMETER 表示这个 Annotation 可以用在 Type 的声明式前,而 ElementType .TYPE_USE 表示这个 Annotation 可以用在所有使用 Type 的地方(如:泛型,类型转换等)。
Type Annotation 也可以通过设置 Retention 在编译后保留在 class 文件中(RetentionPolicy.CLASS)或者运行时可访问(RetentionPolicy.RUNTIME)。但是与之前不同的是,Type Annotation 有两个新的特性:在本地变量上的 Annotation 可以保留在 class 文件中,以及泛型类型可以被保留甚至在运行时被访问。
此外,JAVA8中还增加了一个特性RepeatingAnnotation,允许为同一个声明式或者类型加上相同的 Annotation。
例如:一个类可以被两个人使用:
@Worker(role="XiaoMing") @Worker(role="XiaoHong") public class Person { ... }
需要需要重复标注特性的 Annotation 前加上 @Repeatable 标签
@Repeatable(Workers.class) public @interface Worker{ String role(); }@Repeatable 标签后括号中的值即为指定的 Container Annotation 的类型。在这个例子中,Container Annotation 的类型是 Workers,Java 编译器会把重复的 Worker 对象保存在 Workers中。
Workers中必须定义返回数组类型的value()方法。数组中元素的类型必须为对应的 Repeating Annotation 类型。具体示例如下:
public @interface Workers{ Worker[] value(); }获取注解的方法有两种:
一种方式是用过 上述的的 getAnnotations(Class<T>) 方法一次性返回 Repeating Annotation。
另一种方式是通过 AnnotatedElement 接口的 getAnnotationByType(Class<T>) 首先获得 Container Annotation,然后再通过 Container Annotation 的 value 方法获得 Repeating Annotation。
Workers workers= Person.class.getAnnotation(Workers.class); Worker[] workers2= Person.class.getAnnotationsByType(Worker.class);以上关于JAVA8中的注解参考 http://www.ibm.com/developerworks/cn/java/j-lo-java8annotation/index.html
6.Android中的注解
6.1两个常见的注解
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.XX) { //高于XX版本进行的操作 } else { //低于XX版本进行的操作 }
6.2Android中用到的注解
6.2.1 @CallSuper
6.2.2 @NonNull和@Nullable
6.2.3 资源类注解
getDrawable(@DrawableRes int id) //getDrawable方法限定了传入的参数必须是Drawable资源文件
6.2.4@IdDef和@StringDef
public static final int LENGTH_SHORT = 0; public static final int LENGTH_LONG = 1;
@IntDef({LENGTH_SHORT, LENGTH_LONG}) @Retention(RetentionPolicy.SOURCE) public @interface Duration {}
6.2.5 范围约束@FloatRange、@IntRange和@Size
6.2.6 进程类注解
@WorkerThread protected abstract Result doInBackground(Params... params){ //doInBackground } @MainThread protected void onProgressUpdate(Progress... values) { //onProgressUpdate }
6.2.7@CheckResult
@CheckResult public boolean checkValid(String value){ return TextUtils.isEmpty(value); }
6.2.8 权限注解@RequiresPermission
6.2.9 @SdkConstant
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_MY_TEST = "android.intent.action.MY_TEST";
Intent myTest = new Intent(Intent.ACTION_MY_TEST); mContext.sendBroadcast(myTest);