abstract
- 什么是java中的注解
- 注解的定义
- 自定义一个注解
什么是java中的注解
注解提供了一种安全的类似注释的机制.用来将 任何的信息或者元数据 (metadata)与程序元素( 类,方法,成员变量等 )进行关联,为程序的元素加上更加直观的说明,这些说明信息与程序的业务逻辑无关,是由 指定的工具或框架 来实现的.Annotation像修饰符一样,应用于包,类型构造方法,方法,成员变量,参数,及本地变量的声明语句中.
注解的定义
先看下面的例子
//下面两个是必须的元注解,分别确定了这个注解的作用对象(类的方法)和生命周期(这个注解会被保存在class文件中,并且直到运行时也不会被丢弃)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
//此处定义了注解可以接受一个数据类型为int的元数据
int value();
}
所以,定义一个注解分为三步
- 跟类(class),接口(interface),枚举(enum)一样,注解的定义有自己的关键字(@interface)
- 定义注解时需要元注解的定义(之前已经提到过了,注解作用的对象是类,方法,成员变量等,那么元注解作用的对象就是注解本身),一般有下面几个元注解
- @Target 用来标注注解的作用对象,是类,方法,还是成员变量
- @Retention 用来标注注解的生命周期,有三种 1.RetentionPolicy.SOURCE,表示这个注解只出现在源码中,编译时会被编译器抛弃 2.RetentionPolicy.CLASS,这种是注解的默认状态,表示这个注解会被保存到class文件中,但是到了runtime就会被抛弃 3.RetentionPolicy.RUNTIME,这表示注解会保留到运行时
- @Documented 它的作用是能够将注解中的元素包含到Javadoc中去
- @Inherited Inherited 是指继承,@Inherited 定义了一个注释与子类的关系。如果一个超类带有 @Inherited 注解,那么对于该超类,它的子类如果没有被任何注解应用的话,那么这个子类就继承了超类的注解
- @Repeatable 用这个元注解修饰之后,注解可以重复赋值
3.最后,需要在注解内部定义方法,接收使用注解时在注解后面的赋值
自定义一个注解
现在我们举个栗子,自定义一个简单的butterknife注解,实现两个功能,一是直接注解成员变量得到控件的对象,而是直接成员方法得到控件的点击事件
获取控件引用的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindClick {
int value();
}
绑定点击事件的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface BindView {
//此处定义了注解可以接受一个数据类型为int的元数据
int value();
}
最重要的一个类,读取这两个注解的值,并且将其实现的框架类,通过注入一个activity对象,就可以解析所有activity里面的注解,并完成相应的功能
public class ButterKnife {
public static void inject(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
if (field.isAnnotationPresent(BindView.class)) {
BindView annotation = field.getAnnotation(BindView.class);
int resId = annotation.value();
field.setAccessible(true);
try {
field.set(activity, activity.findViewById(resId));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
if (method.isAnnotationPresent(BindClick.class)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
BindClick declaredAnnotation = method.getDeclaredAnnotation(BindClick.class);
int resId = declaredAnnotation.value();
method.setAccessible(true);
View viewById = activity.findViewById(resId);
viewById.setOnClickListener(v -> {
try {
method.invoke(activity, v);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
});
}
}
}
}
}
最后一步,在activity中编写相应的注解,并且调用ButterKnife.inject(this)就可以了
public class MainActivity extends AppCompatActivity {
@BindView(R.id.tv_title)
TextView tvTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
tvTitle.setText(getResources().getString(R.string.app_name));
}
@BindClick(R.id.tv_title)
public void onTitleClick(View view) {
Toast.makeText(this, getResources().getString(R.string.app_name), Toast.LENGTH_SHORT).show();
}
}
网友评论