总结于这位大佬的博客
定义:上面大佬的博客中将注解比作标签,我这边的理解不同,因为标签可以随便贴在哪个瓶子上但是瓶子本身的性质、能力等没有变化。注解实际上是让一个事物拥有了更多特性,一个注解对应一种特性,被该注解标记的事物就拥有了这种特性,就好比游戏里镶嵌在宝剑上的宝石,有加攻击的宝石、有加攻速的宝石等等。
创建注解:public @interface TestAnnotation{}
使用:在需要的地方加上 @TestAnnotation(),如果该注解没有任何属性则可以省略()即@TestAnnotation
元注解
定义
给注解注解的注解,有五种:@Retention、@Documented、@Target、@Inherited、@Repeatable
@Retention:时间标签
取值: RetentionPolicy.SOURCE 注解存活在源码阶段,编译时丢弃
RetentionPolicy.CLASS 注解存活到编译,不会加载到JVM中
RetentionPolicy.RUNTIME 注解存活到程序运行,加载到JVM中,在程序运行时可以获取注解
使用: @Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation{}
@Documented:将注解中的元素包含到 Javadoc 中去
@Target:注解使用限制
取值: ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
@Inherited:注解可以继承,如果一个类被该注解注解的注解注解了,他的子类没有其他注解的话也拥有改注解
@Repeatable:可使用多次
声明方式:
@Repeatable(Peoples.class)
@interface People
{
String role() default "";
}
如果想要给被注解的东西注解多次则可以使用@Repeatable
使用前需要创建一个注解容器用来存放这些注解,注解容器拥有是集合类型的属性的注解
@interface Peoples
{
People[] value();
}
使用:
@People(role="artist")
@People(role="driver")
public class me{
}
注解的属性
普通类变量,但是变量名后面要加(),默认值用default指定
public @interface TestAnnotation {
public int id() default -1;
}
使用时
@TestAnnotation() 这时id用默认值
@TestAnnotation(id=2) 也可以@TestAnnotation(2),因为只有一个属性
Java 预置的注解
@Deprecated:标记过时的元素,如果被改注解的方法被调用会有个删除线
@Override:帮助自己检查是否正确的复写了父类中已有的方法(自动检查父类中是否有这个方法,方法的参数是否和父类中的一致)并且告诉读代码的人,这是一个复写的方法
@SuppressWarnings:阻止警告,使用@Deprecated注解过的方法时会有警告,
@SuppressWarnings("deprecation")忽略警告
@SafeVarargs:参数安全类型注解,提醒开发者不要用参数做一些不安全的操作
@FunctionalInterface:函数式接口注解,即一个具有一个方法的普通接口,函数式接口可以很容易转换为 Lambda 表达式,比如经常用到的Runnable
使用注解
- 运行时使用:通过反射获取相应的类、属性或者方法
调用
getAnnotation 获取指定类型的注解,没有返回null
getAnnotations 返回所有注解
isAnnotationPresent 判断是否有指定类型的注解,有true,没有false
getDeclaredAnnotations 返回直接存在于此元素上的所有注释,不包含继承过来的注解 - 编译时使用:在某些代码元素上(如类型、函数、字段等)添加注解;
编译时编译器会检查AbstractProcessor的子类,
然后将添加了注解的所有元素都传递到该类的process函数中;
使得开发人员可以在编译器进行相应的处理。
实例
android jetpack中的Lifecycle关于注解的使用
注解类:OnLifecycleEvent
@SuppressWarnings("unused")
@Retention(RetentionPolicy.RUNTIME)//由于需要在Activity创建后动态绑定观察者,所以这边是运行时
@Target(ElementType.METHOD) //只会用在方法上面
public @interface OnLifecycleEvent {
Lifecycle.Event value();
}
//观察者,这边使用播放器去观察Activity的生命周期
public class VideoPlayer implements LifecycleObserver{
//添加注解,在Activity创建时自动创建播放器
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void createPlayer(){
....
}
}
//被观察者,Activity
public class Activity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
//添加生命周期观察,这时当Activity创建完,播放器会自动创建
getLifecycle().addObserver(mVideoPlayer);
}
}
在运行时通过反射将需要在相应生命周期触发的方法保存下来
实际保存的类是ClassesInfoCache
private CallbackInfo createInfo(Class klass, @Nullable Method[] declaredMethods) {
...
//通过反射获取注解
Method[] methods = declaredMethods != null ? declaredMethods : getDeclaredMethods(klass);
booleanhasLifecycleMethods = false;
for (Method method : methods) {
OnLifecycleEvent annotation = method.getAnnotation(OnLifecycleEvent.class);
if (annotation == null) {
continue;
}
//使用一个map来保存
verifyAndPutHandler(handlerToEvent, methodReference, event, klass);
}
...
|
当Activity相应生命周期发生时会调用ClassesInfoCache中invokeCallbacks来触发
void invokeCallback(LifecycleOwner source, Lifecycle.Event event, Object target) {
//noinspection TryWithIdenticalCatches
try {
switch (mCallType) {
case CALL_TYPE_NO_ARG:
mMethod.invoke(target);
break;
case CALL_TYPE_PROVIDER:
mMethod.invoke(target, source);
break;
case CALL_TYPE_PROVIDER_WITH_EVENT:
mMethod.invoke(target, source, event);
break;
}
} catch (InvocationTargetException e) {
throw new RuntimeException("Failed to call observer method", e.getCause());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}