在android的开发中注解使用是非常常见的,注解可以使代码阅读更加的清晰,整洁,可读性大大增强。
注解的原理:
使用interface来用作标记,@Target来用作描述类型(包括类、成员变量、方法等)@Retention来描述生命周期。其内部是通过类的反射机制,调用指定对象的方法,从而达到与对象直接调用方法相同的效果。
一、注解作用
在Java开发中,注解一般有以下功能:
标识
java SE5,在jdk中,类似我们比较常见的注解有Override,Deprecated,SuppressWarnings,这些作用只是作为标识,删除对程序没影响。他们的作用分别为:
Override 表示这个方法重写了父类的方法
Deprecated 表示jdk中不建议使用这个方法或者属性
SuppressWarnings 表示屏蔽了某些警告
java8 新特性:Repeatable 表示允许多次使用同一个注解
运行时处理
这个编译器默认的做法,编译器会通过class文件,逐个逐个的遍历class的属性和方法,即运行时处理。
编译时处理
在运行之前,有学过C的程序猿就会知道,编译器在运行之前,编译的时候会将include进来的*.h文件进行引入。同理例如你在代码中引入注解,编译器会在编译的时候,将注解的属性引入再进行编译。
二、注解基础
先看一个简单自定义注解
@Target(ElementType.TYPE) //用于描述类
@Retention(RetentionPolicy.RUNTIME) //运行时注解
public @interface ContentView {
//注解的值
int value();
}
这上面记得要添加一个@,不然就变成定义一个接口。在这里,value()不是代表一个方法,而是代表一个属性,其中value是属于整形的属性,默认值为1。
自定义的上面的@Target,@Retention就是传说中的元注解,下面看下元注解
元注解 | 作用 |
---|---|
@Target | 表示该注解可以用于什么地方,可能在ElementType参数包括: **CONSTRUCTOR: 用于描述构造器 FIELD: 用于描述域 LOCAL_VARIABLE: 用于描述局部变量 METHOD: 用于描述方法 PACKAGE: 用于描述包 PARAMETER: 用于描述参数 TYPE: **用于描述类、接口(包括注解类型) 或enum声明 |
@Retention | 表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括: SOURCE: 注解将被编译器丢弃 CLASS: 注解在class文件中可用,但会被VM丢弃。 RUNTIME: VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息 |
@Document | 将此注解包含在javadoc中 |
@Inhrited | 允许子类继承父类中的注解 |
java 8新特性:java 8之前注解只能是在声明的地方所使用,比如类,方法,属性;java 8里面,注解可以应用在任何地方,比如方法参数前面等。
三、自定义注解的格式
public @interface 注解名{注解体}。注解体中注解元素可以被public修饰,也可以什么也不写,元素类型可以是:
- 所有基本数据类型(int,float,boolean等八种基本类型)
- String类型
- Class类型
- enum类型
- Annotation类型(说明注解可以嵌套)
- 以上所有类型的数组
默认值的限定
编译器对默认值过分的挑剔,要么有确定的默认值,要么在使用的时候提供元素的值。
基本类型的元素都有默认值,不用写default也可以,但是想String这类就必须要写,而且不能写null,因此在某些需要分清是null还是空字符串的地方要注意。
四、自定义注解
注解声明:
@Target(ElementType.TYPE) //用于描述类
@Retention(RetentionPolicy.RUNTIME) //运行时注解
public @interface ContentView {
//注解的值,默认为1,可不写
int value() default 1;
}
标记类:
@ContentView(R.layout.activity_main)
public class DemoActivity extends AppCompatActivity {
@FindView(R.id.btn1)
private AppCompatButton mBtn1;
@FindView(R.id.btn2)
private AppCompatButton mBtn2;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
injectContentView(this);
}
}
injectContentView(this)负责将值注入:
/**
* 通过反射将值注入
*
* @param activity
*/
private void injectContentView(Activity activity) {
//获取activity对应的class
Class a = activity.getClass();
//判断当前class是否有ContentView的注解
if (a.isAnnotationPresent(ContentView.class)) {
//获取注解实例
ContentView contentView = (ContentView) a.getAnnotation(ContentView.class);
//获取注解中的值
int layoutIt = contentView.value();
try { //获取class的方法,第一个参数是方法名,第二个是方法参数的类型
Method method = a.getMethod("setContentView", int.class);
method.setAccessible(true);
//调用指定对象的此方法,第二个是方法的参数
method.invoke(activity, layoutIt);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
这里就只是简单的介绍了注解!还有好多东西后面慢慢写
网友评论