今天记录下注解的小代码
关于注解,一直在使用,了解少许,没有时间总结,这里记录下,共勉
注解包含太多了, 这里只记录下基本的语法 和使用
1 定义声明
通过 @interface 关键字进行定义
public @interface testInject {
}
结构与接口声明类似 ,仅仅多了个@ 。上面就定义了个名为testInject的注解。
注解里只有属性,没有方法, 属性以“无形参的方法”形式来声明,其方法为属性名,其返回值为属性类型。
注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。
public @interface testInject {
int id();
String text();
}
上面代码定义了 TestInject 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们可以给它们进行赋值
注解时可以对定义属性进行默认赋值,当无赋值时他们的值就是定义默认值 默认值需要用 default 关键值指定
public @interface testInject {
int id() default -1;;
String text() default "ruiyi";
}
2 注解的赋值赋值的方式是在注解的括号内以 value=”” 形式,多个属性之前用 ,隔开。
@testInject(id = 4, text = "world")
public class Test{
}
因为有默认值,所以无需要再在 @TestInject 后面的括号里面进行赋值了,这一步可以省略。 @testInject()
public class Test{
}
另外,还有一种情况。如果一个注解内仅仅只有一个属性时,应用这个注解时可以直接接属性值填写到括号内 @testInject(4)
public class Test{
}
3 元注解元注解是可以注解到注解上的注解,或者说元注解对注解进行解释说明
元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
3.1
@Retention 注解的生命周期。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
它的取值如下:
RetentionPolicy.SOURCE 在源文件中有效(即源文件保留),在编译器进行编译时它将被丢弃忽视。
RetentionPolicy.CLASS 在class文件中有效(即class保留),它并不会被加载到 JVM 中。
RetentionPolicy.RUNTIME 在运行时有效(即运行时保留),它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
3.2
@Documented
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
3.3
@Target 指定了注解运用的地方。
@Target 有下面的取值
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 用于描述构造器
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
3.4
@Inherited
Inherited 继承,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
3.5
@Repeatable
Repeatable 自然是可重复的意思 (有时间详解)
4 初试 这里我们以注解的形式 来模拟findViewById的操作。
4.1 定义注解
控件注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by ruiyi on 2017/8/10.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value() default -1;
}
//布局注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by ruiyi on 2017/8/10.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LayoutInject {
int value() default -1;
}
4.2定义一个注解基类package ruiyi.testInject;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import java.lang.reflect.Field;
/**
* Created by ruiyi on 2017/8/10.
*/
public class InJectActivity extends AppCompatActivity {
private int mLayoutId = -1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
InjectLayout();
InjectView();
}
/**
* 注解布局Layout id
*/
private void InjectLayout() {
Class<?> clazz = this.getClass();
if (clazz.getAnnotations() != null) {
if (clazz.isAnnotationPresent(LayoutInject.class)) {
LayoutInject inject = clazz.getAnnotation(LayoutInject.class);
mLayoutId = inject.value();
setContentView(mLayoutId);
}
}
}
/**
* 解析注解view id
*/
private void InjectView() {
if (mLayoutId <= 0)
return;
Class<?> clazz = this.getClass();
Field[] fields = clazz.getDeclaredFields();//获得成员变量
for (Field field : fields) {
//判断是否有注解
try {
if (field.getAnnotations() != null) {
if (field.isAnnotationPresent(ViewInject.class)) {//如果属于这个注解为这个控件设置属性
field.setAccessible(true);//允许修改反射属性
ViewInject inject = field.getAnnotation(ViewInject.class);
field.set(this, this.findViewById(inject.value()));
}
}
} catch (Exception e) {
Log.e("ASDFGHJKL", "not found view id!");
}
}
}
}
4.3 具体类package ruiyi.testInject;
import android.os.Bundle;
import android.widget.TextView;
@LayoutInject(R.layout.activity_main)
public class MainActivity extends InJectActivity {
@ViewInject(R.id.tv)
TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTextView.setText("ruiyi");
}
}
上面就以注解实现了findViewById 和 布局setContent功能。
我这里赘述一点,解释下
首先LayoutInject, 我们定义有效期为运行时,target为tyoe,作用在类上使用,类型为int值,默认-1,赋值代码@LayoutInject(R.layout.activity_main) 相当于@LayoutInject(value = R.layout.activity_main) , 取值时,因为指向类,LayoutInject inject = clazz.getAnnotation(LayoutInject.class); 类对象直接取注解对象,然后mLayoutId = inject.value(); 取属性值, 最后setContentView(mLayoutId);
再说ViewInject, 定义也是运行时,作用在属性上FIELD, 由于是属性,所以取时首先获取属性,也就是clazz.getDeclaredFields();//获得成员变量,由于反射机制,防止是private的field.setAccessible(true);//允许修改反射属性
就这样