Android 开发也要掌握的Java知识 - Java注解
2020-08-17 本文已影响0人
进击的包籽
- Android开发中大量的使用了注解,开源框架也大量使用,我们自己虽然自定义的注解不多,但也要了解基本的知识。
1.注解的定义
- Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 注解是元数据的一种形式,提供有关
于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。
2.注解是什么样的
- Java中所有的注解,默认实现 “Annotation ”接口
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
- 平时我们见到的最多就是重写注解吧,只要子类重写了父类的方法,都会出现这个注解。

- 看看这个 “@Override” 源码,注解的写法是 “@interface” ,跟接口有没有很像?,但前面多了一个 “ @” 符号
- 而且这个注解上面还有注解,这就是元注解

3.注解的分类以及作用
- 我这里整理了一些,自己写注解,不熟悉就翻来看看,用的多久熟悉了

4.注解写法
- 只有一个默认参数value 时,可以不写参数“key = ”,以下两种写法一样样效果
//作用在什么地方:类、接口、方法、属性变量
@Target({ElementType.TYPE,ElementType.METHOD, ElementType.FIELD})
//生命周期在运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
//如果使用value,用的时候可以是 “value = 111”,也可以直接写 “111”
int value();
}
@TestAnnotation(111)
private int num1;
@TestAnnotation(value = 111)
private int num2;
- 如果要传入的参数不止一个,那么 “value = 111” 就一定要写全
- 如果有“default”默认参数了,就可以不用传参
- “default”也可以再传参覆盖原来的值
//作用在什么地方:类、接口、方法、属性变量
@Target({ElementType.TYPE,ElementType.METHOD, ElementType.FIELD})
//生命周期在运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
//如果使用value,用的时候可以是value = 111,也可以直接写 111
int value();
//自己创建一个data1参数,就要写value = 111, data1 = "111",且前面value也要写全
String data1();
//如果有default默认值,可以不写这参数,也能加上data2 = "222"修改参数
String data2() default "222";
}
@TestAnnotation(value = 111,data1 = "111")
private int num1;
@TestAnnotation(value = 111,data1 = "111",data2 = "333")
private int num2;
5.注解使用
5.1 过时标记
-
过时标记“ @Deprecated”,是Java自带的,这个注解标记过的,都会划上横线,就是不推荐在使用了
过时
5.2 语法检查
- 语法检查注解“@IntDef”,限制了参数类型,可以用来替代枚举类型
- Android中还有很多 @DrawableRes、@IdRes、@StringRes、@AnimRes等等,后面带上“Res”就是限制传入的参数类型了
public class WeekDay {
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
//有效期在源码阶段,用于语法校验
@Retention(RetentionPolicy.SOURCE)
//该注解修饰属性、修饰方法参数
@Target({ElementType.FIELD, ElementType.PARAMETER})
//传入的类型只能是这几个
@IntDef({MONDAY, TUESDAY, WEDNESDAY})
public @interface WeekDayAnnotation {
}
}
- 我们可以看到写 1,会报错,提示只能传的类型

5.3 findViewById
- 不需要重复写findViewById,直接给控件加上注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
@IdRes int value();
}
/*--------------------------------------------------------*/
public class InjectViewUtils {
public static void injectView(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
//获取成员
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//判断是否被打上了InjectView注解标签
if (field.isAnnotationPresent(InjectView.class)) {
InjectView injectView = field.getAnnotation(InjectView.class);
//获取View的id
int id = injectView.value();
View view = activity.findViewById(id);
//反射设置值
//设置权限,允许修改private的属性
field.setAccessible(true);
try {
field.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
- 使用
@InjectView(R.id.tvTest)
private TextView tvTest;
@InjectView(R.id.tvTest2)
private TextView tvTest2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectViewUtils.injectView(this);
}
5.4 View的Onclick
- 不需要拿到View,也不用写View的Onclick监听,直接加注解,省事
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectOnClick {
@IdRes int[] value();
}
/*------------------------------------------------------*/
/**
* 点击事件处理
*/
public class OnClickUtils {
static public void inject(final Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
//获取所有方法
Method[] methods = clazz.getDeclaredMethods();
for (final Method method : methods) {
//判断方法的注解类型
if (method.isAnnotationPresent(InjectOnClick.class)) {
InjectOnClick injectOnClick = method.getAnnotation(InjectOnClick.class);
//获取id参数数组
int[] ids = injectOnClick.value();
//设置权限,可以修改private
method.setAccessible(true);
for (int id : ids) {
//每个id都设置
activity.findViewById(id).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//调用方法回传
try {
method.invoke(activity);
} catch (Exception e) {
e.printStackTrace();
try {
method.invoke(activity, v);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
});
}
}
}
}
}
- 使用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OnClickUtils.inject(this);
}
@InjectOnClick({R.id.tvTest, R.id.tvTest2})
private void OnClick(View view) {
int id = view.getId();
if (id == R.id.tvTest) {
} else if (id == R.id.tvTest2) {
}
}
6.结尾
- 注解使用简单,但经常需要配合反射技术,后续有学习更多注解知识,就分享给大家。