注解
Annotation:Java提供的一种元程序中的元素关联任何信息或者任何元数据(metadata)的途径和方法
基本规则:Annotation(注解)不能影响程序代码的执行,无论增加,删除注解,代码都始终如一的执行
元数据(metadata)
1、以标签的形式存在于Java代码中
2、描述的信息是类型安全的
3、需要编译器之外的工具额外的处理用来生成其他的程序部件
4、可以存在于Java源代码级别,也可以存在于Java代码编译之后的class文件内部
元注解
用来定义其他注解的注解,四种元注解:@Retention、 @Target、@Inherited、@Documented。
@Target
表示使用范围,如:@Target(ElementType.METHOD),参数是一个ElementType类型的数组
参数 | 说明 |
---|---|
TYPE | 类,接口(包括注释类型)或enum声明 |
FIELD | 域声明(包括enum实例) |
METHOD | 方法声明 |
PARAMETER | 参数声明 |
CONSTRUCTOR | 构造器的声明 |
LOCAL_VARIABLE | 局部变量声明 |
ANNOTATION_TYPE | 注解类型声明 |
PACKAGE | 包声明 |
TYPE_PARAMETER | 输入参数声明 |
TYPE_USE | 使用类型声明 |
@Retention
表示在什么级别保存注解信息,如:@Retention(RetentionPolicy.SOURCE)
参数 | 说明 |
---|---|
SOURCE | 注解将被编译器丢弃 |
CLASS | 注解在class文件中谁用,但会被JVM抛弃 |
RUNTIME | 在运行期也保留注解信息,可通过发射机制读取注解信息 |
@Document
标记的注解可以被javadoc此类的工具文档化
@inherited
表明我们标记的注解是被继承的。如果一个父类使用了@Inherited修饰的注解,则允许子类继承该父类的注解。
常用Java注解
@Override
子类对父类方法的重写所带的注解
@Deprecated
表示已经过时,不建议使用,但是依然可以使用
@SuppressWarnings
用来抑制编译时的警告信息,如:@SuppressWarnings(“all”)
参数 | 说明 |
---|---|
deprecation | 过滤使用了过时的类或方法的警告 |
unchecked | 过滤执行了未检查的转换警告 |
fallthrough | 过滤switch语句发生case穿透的警告 |
path | 过滤类路径,源文件路径等路径不存在的警告 |
serial | 过滤可序列化类上缺少serialVersionUID定义时的警告 |
finally | 过滤任何finally子句不能完成时的警告 |
all | 过滤所有情况的警告 |
常用Android注解
@NonNull
声明方法的参数不能为空
@Nullable
表示一个方法的参数或者返回值可以是Null的
@CallSuper
重写的方法必须要调用super方法
@RequiresPermission
辅助发现需要申请的权限
@CheckResult
用来注解方法,如果一个方法得到了结果,却没有使用这个结果,就会有错误出现
@Keep
不混淆
Resource Type(资源类型)
指定传入参数的类型,通常用于传入资源的方法中,资源注解如下:AnimRes,AnimatorRes,AnyRes,ArrayRes,AttrRes,BoolRes,ColorRes,DimenRes,DrawableRes,FractionRes,IdRes,IntegerRes,InterpolatorRes,LayoutRes,MenuRes,PluralsRes,RawRes,StringRes,StyleRes,StyleableRes,TransitionRes,XmlRes
@ColorInt
限定颜色资源id
Threading相关
@UiThread
通常可以等同于主线程,标注方法需要在UIThread执行
@MainThread
主线程,经常启动后创建的第一个线程
@WorkerThread
工作者线程,一般为一些后台的线程,如AsyncTask的doInBackground()
@BinderThread
注解方法必须要在BinderThread线程中执行,使用较少
自定义注解
案例一
1 //自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CalculateMethodRunningTime {
//String为返回值类型,methodName为方法名,default表示使用注解时未指定参数
String methodName() default "no method to set";
}
2 //构建注解功能
public static void getClassInfo(String className) {
try {
Class c = Class.forName(className);
//获取所有公共的方法
Method[] methods = c.getMethods();
for(Method m : methods) {
Class<CalculateMethodRunningTime> ctClass = CalculateMethodRunningTime.class;
if(m.isAnnotationPresent(ctClass)){
CalculateMethodRunningTime anno = m.getAnnotation(ctClass);
//当前方法包含查询时间的注解时
if(anno != null){
long beginTime = System.currentTimeMillis();
m.invoke(c.newInstance(),null);
long endTime = System.currentTimeMillis();
long time = endTime - beginTime;
Log.i("Tag",anno.methodName()+"方法执行所需要时间:" + time + "ms");
...
3 //使用注解,注意getClassInfo传入的是自定义注解的全包名
AnnotationUtils.getClassInfo("demo.com.mycamear.ActivityAnnotattion");
method1();
案例二
//自定义注解
@Documented
//适用时机
@Retention(RetentionPolicy.RUNTIME)
//适用范围
@Target({ElementType.FIELD,ElementType.METHOD})
@interface MyTarget{
String name();
int age();
int getScore() default 0;
}
//应用于Bean类
public class MyStudent{
//同时设置自定义注解的三个属性
@MyTarget(name = "lishan", age = 12,getScore = 111)
public String name;
//值设置自定义注解的两个属性,因为getScore属性有默认值,可以不设置
@MyTarget(age = 14, name = "zhansan")
public int age;
//将自定义注解设置在方法上
@MyTarget(age = 13,name = "wangwu")
public void method(){}
}
//使用
AnnoationUtils.getInfo(MyStudent.class);
//相关引用
public class AnnoationUtils{
private static final String TAG = "AnnoationUtils";
public static void getInfo(Class<?> beanClazz){
//获取Bean类所有公共成员变量
Field[] fields = beanClazz.getDeclaredFields();
//遍历Bean类所有公共成员变量
for (Field field : fields){
//判断成员变量的注解
if (field.isAnnotationPresent(MyTarget.class)){
//获取成员变量的注解
MyTarget myTarget = field.getAnnotation(MyTarget.class);
Log.e(TAG, myTarget.name());
}
}
Method[] methods = beanClazz.getDeclaredMethods();
for (Method method : methods){
if (method.isAnnotationPresent(MyTarget.class)){
MyTarget mytarget = method.getAnnotation(MyTarget.class){
mytarget.getScore()
}}}}}