注解
注解 Java提供了一种源程序中的元素关联任何信息和任何元数据的途径和方法 注解分类
源码注解(RetentionPolicy.SOURCE) 注解只在源码中存在,编译成.class文件就不存在了 编译时注解(RetentionPolicy.CLASS) 注解在源码和.class文件中都存在 通过自定义的注解处理器,在编译时动态生成类 运行时注解(RetentionPolicy.RUNTIME) 在运行阶段还起作用,甚至会影响运行逻辑的注解 在运行阶段通过反射来获取注解信息和调用
自定义注解
import java. lang. annotation. Documented;
import java. lang. annotation. ElementType;
import java. lang. annotation. Inherited;
import java. lang. annotation. Retention;
import java. lang. annotation. RetentionPolicy;
import java. lang. annotation. Target;
@Target ( { ElementType. METHOD, ElementType. TYPE} )
@Retention ( RetentionPolicy. RUNTIME)
@Inherited
@Documented
public @interface Description {
String name ( ) ;
int age ( ) default 18 ;
}
@Description
public void test ( ) {
}
元注解(注解的注解)
Target(注解的作用域)
TYPE(类、接口) FIELD(字段声明,包括枚举常量) METHOD(方法声明) PARAMETER(参数声明) CONSTRUCTOR(构造方法声明) LOCAL_VARIABLE(局部变量声明) PACKAGE(包声明) Retention(生命周期)
SOURCE(只在源码显示,编译时丢弃) CLASS(编译时会记录到class中,运行时忽略) RUNTIME(运行时存在,可以通过反射来读取) Inherited 允许子类继承 Documented 生成javadoc时会包含注解信息
提取注解(通过反射)
首先通过Class对象的isAnnotationPresent()方法判断它是否应用了某个注解
javaClass. isAnnotationPresent ( Nullable:: class . java)
然后通过getAnnotation()或者getAnnotations()方法获取Annotation对象
解析注解
通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑
public static void get ( Object object) {
Class clazz = object. getClass ( ) ;
Method[ ] methods = clazz. getMethods ( ) ;
for ( Method method : methods) {
if ( method. isAnnotationPresent ( Description. class ) ) {
Description annotation = method. getAnnotation ( Description. class ) ;
if ( annotation != null) {
Log. d ( TAG, "get: " + annotation. name ( ) ) ;
}
}
}
}
使用注解实现一个类似于ButterKnife的注入功能
import java. lang. annotation. ElementType;
import java. lang. annotation. Retention;
import java. lang. annotation. RetentionPolicy;
import java. lang. annotation. Target;
@Target ( { ElementType. FIELD} )
@Retention ( RetentionPolicy. RUNTIME)
public @interface ViewById {
int value ( ) ;
}
import android. app. Activity;
import java. lang. reflect. Field;
public class ViewByIdUtils {
public static void register ( Object object ) {
Field[ ] fields = object . getClass ( ) . getDeclaredFields ( ) ;
for ( Field field :
fields) {
field. setAccessible ( true ) ;
ViewById viewById = field. getAnnotation ( ViewById. class) ;
if ( viewById != null ) {
try {
field. set ( object , ( ( Activity) object ) . findViewById ( viewById. value ( ) ) ) ;
} catch ( IllegalAccessException e) {
e. printStackTrace ( ) ;
}
}
}
}
}
@ViewById ( R. id. bt_test)
Button button;
@Override
protected void onCreate ( Bundle savedInstanceState) {
super . onCreate ( savedInstanceState) ;
setContentView ( R. layout. activity_main2) ;
ViewByIdUtils. register ( this ) ;
button. setText ( "你好" ) ;
}
还可以进行一些改造,例如不需要对@ViewById设置参数,这种情况可以将View变量的命名和xml中一致
if ( viewById. value ( ) == - 1 ) {
try {
field. set ( object , ( ( Activity) object ) . findViewById ( getViewIdByName ( object , field. getName ( ) ) ) ) ;
} catch ( IllegalAccessException e) {
e. printStackTrace ( ) ;
}
}
public static int getViewIdByName ( Object object , String resName) {
return ( ( Activity) object ) . getResources ( ) . getIdentifier ( resName, "id" , ( ( Activity) object ) . getPackageName ( ) ) ;
}