从jdk1.5开始java提供了注释功能,允许开发者定义和使用自己的注释类型。
该功能由一个定义注释类型的语法和描述一个注释声明的语法,读取注释的API;一个使用注释修饰的class文件和一个注释处理工具组成。
首先,其语法定义形式为@interface,其含义为声明一个注释类的关键字。
使用@interface表示我们已经继承了java.lang.annotation.Annotation类,这是一个注释的基类接口。就好像Objcet类.
annotation 是注释 注解的意思
其语法还有一条规定:在定义注释时,不能继承其他的注释或接口。
public @interface MyAnnotation{
}
然后通常在使用时我们都会给这个注释类加上两个注释
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
ElementType、RetentionPolicy 是两个枚举类,ElementType.FIELD表示我们需要注释的是一个字段。
ElementType枚举常量摘要
ANNOTATION_TYPE 注释类型声明
CONSTRUCTOR 构造方法声明
FIELD 字段声明
LOCAL_VARIABLE 局部变量声明
METHOD 声明方法
PACKAGE 包声明
TYPE 类接口或枚举声明
RetentionPolicy 枚举常量摘要
CLASS 编译器将把注释记录在类文件中,但在运行时VM不需要保留注释
RUNTIME 编译器将把注释记录在类文件中,在运行时VM将保留注释,因此可以反射性地读取.
SOURCE 编译器要丢弃的注释
使用注释
//声明注释
@Target(Element.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView{
public int id();
public boolean click() default false;
}
使用注释
@BindView(id=R.id.x,click=true) private TextView t;
我们可以看到。除了明显减少了代码量,还使得代码结构更佳清晰.
其中,定义部分的id()表示注释接受一个int类型的数据作为id对应的值
同理,定义部分的click表示接受一个Boolean类型的数据作为click对应的值,还可以设置一个默认值使用default修饰.
处理注释:
我们已经知道了注释怎么定义和使用,接下来就应该知道怎么处理了。
bindView注释可以接受一个int类型的值和一个boolean类型的值.那么这两个值接收了以后如何获取呢?
其实获取的方法很简单就是通过一个bindView类型的对象,调用这个对象来自声明中定义的两个方法->id()或click()方法。
现在有一个问题,注释类型是不能直接new 对象的,那么这个bindView对象从那里来呢?
这是就需要用到Java的反射机制。我们知道每一个继承自object类的类都会继承一个getClass()方法,下面看一下这个方法的原型。
/**
* Returns the unique instance of {@link Class} that represents this
* object's class. Note that {@code getClass()} is a special case in that it
* actually returns {@code Class<? extends Foo>} where {@code Foo} is the
* erasure of the type of the expression {@code getClass()} was called upon.
* <p>
* As an example, the following code actually compiles, although one might
* think it shouldn't:
* <p>
* <pre>{@code
* List<Integer> l = new ArrayList<Integer>();
* Class<? extends List> c = l.getClass();}</pre>
*
* @return this object's {@code Class} instance.
*/
public final native Class<?> getClass();
这是一个native方法,根据注释我们知道,这个方法返回的是该类的Class对象,同时也是该类的二进制对象。Class中有一个方法叫getDeclareFields(),是用来返回这个类的全部字段,返回类型是Field[]通过Field对象的getAnnotation(Class
public static void initBindView(Object currentClass,View courceView)
{//通过反射获取到全部属性,反射的字段可能是一个类(静态)字段或实例字段
Field[] fields=currentClass.getClass.getDeclareFields();
for(Field fidld:fields)
{
BindView bindView=field.getAnnotation(BindView.class);
if(bindView!=null)
{
int viewId=bindView.id();
boolean clickIs=bindView.click();
try{
field.getAccessible(true);
if(clickIs)
{
sourceView.findViewById(viewId).setOnClickListener((OnClickListener)currentClass)
}
fields.set(currentClass,sourceView.findViewById(viewId))
}catch(Exception e)
{
e.printStachTrace();
}
}
}
}
这是一个静态的方法可以随时调用
可以在你的BaseActivity中进行是用直接传入activity对象
其实安卓中的注释式绑定控件(也是所谓的IOC控制反转在安卓中的一种应用)其实本质的使用就是java基础中反射的使用值得一提的是,反射执行的效率是很低的。
如果不是必要,应当尽量减少反射的使用,因为它会大大的拖累你应用的执行效率。