什么是注解
注解是一种在类、方法、属性、参数、变量等代码中添加一些描述信息,这些数据可以通过反射来获取到,然后针对注解信息做相应操作
为什么要学习注解
- 一些优秀的开源库如Dragger、Retrofit、Butter Knife等都大量使用了注解,理解注解有助于我们学习这些第三方开源库
- android support-annotations库提供了大量注解如@NonNull、@IntgerRes、@Keep等,使用这些注解有助于我们优化代码,增加代码可读性的同性,也能减少错误
Java 元注解的简单说明
- @Target 描述注解的作用区域,常见取值有(TYPE FIELD METHOD PARAMETER)等
- @Retention 描述注解的生命周期
SOURCE 只保留在源码中,如@SuppressWarning作用是在编译时抑制警告,不必写入到class中
CLASS 编译后保留在class文件中,如butterknife框架@Bind 编译时会将注解写入class文件中
RUNTIME 注解会在class字节文件中存在,在运行时可以通过反射获取到相应数据 - @Document 说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
自定义注解
借用别人的一个实例,根据类中注解创建数据库表结构:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
复制代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;
}
复制代码
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primaryKey() default false;
boolean allowNull() default true;
boolean unique() default false;
}
复制代码
@DBTable(name = "MEMBER")
public class Member {
@SQLString(30) String firstName;
@SQLString(value = 30,constraints = @Constraints(primaryKey = true))
String handle;
static int memberCount;
public String getHandle() { return handle; }
public String getFirstName() { return firstName; }
}
复制代码
import java.util.List;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
public class TableCreator {
public static void main(String[] args) throws Exception {
createTab(Member.class);
}
private static void createTab(Class<?> tabClass) {
DBTable dbTable = tabClass.getAnnotation(DBTable.class);
String tableName = dbTable.name(); //读取注解中表名
if (tableName.length() < 1)
tableName = tabClass.getName().toUpperCase();
List<String> columnDefs = new ArrayList<>();
for (Field field : tabClass.getDeclaredFields()) {
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations(); //读取变量注解创建数据表字段
if(anns.length > 0) {
if (anns[0] instanceof SQLString) {
SQLString sString = (SQLString) anns[0];
if (sString.name().length() < 1)
columnName = field.getName().toUpperCase();
else
columnName = sString.name();
columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraints()));
}
}
}
StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
for (String columnDef : columnDefs)
createCommand.append("\n " + columnDef + ",");
String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";
System.out.println("Table Creation SQL for " + tabClass.getName() + " is :\n" + tableCreate);
}
private static String getConstraints(Constraints con) {
String constraints = "";
if (!con.allowNull())
constraints += " NOT NULL";
if (con.primaryKey())
constraints += " PRIMARY KEY";
if (con.unique())
constraints += " UNIQUE";
return constraints;
}
}
复制代码
使用android support-annotations中注解优化代码
- Nullness注解: @Nullable @NonNull
- 资源类注解:@StringRes @IdRes @ColorRes等
- @Keep 保持某个类或者函数不被混淆
- IntDef和StringDef注解
我们出于性能考虑经常用整形代替枚举,假设创建内核时有以下三程类型,我们可以定义一个@CoreType的注解,这样初始化的时候传的不是这三个值,编译器就会报错
public static final int ANDROID_WEBVIEW = 0;
public static final int XWALK_WEBVIEW = 1;
public static final int TENCENT_WEBVIEW = 2;
@IntDef({ANDROID_WEBVIEW, XWALK_WEBVIEW, TENCENT_WEBVIEW})
private @interface CoreType{}
public void init(Context context, @CoreType int coreType) {
mCoreType = coreType
}
复制代码