您的位置:首页 > 其它

自定义注解(Annotation)基本使用

2018-01-28 21:33 741 查看
从 jdk5开始,Java增加了对元数据的支持,也就是Annotation,Annotation其实就是对代码的一种特殊标记,这些标记可以在编译,类加载和运行时被读取,并执行相应的处理。当然刚刚说了,Annotation只是一种标记,所以要是在代码里面不用这些标记也是能完成相应的工作的,只是有时候用注解能简化很多代码,看起来非常的简洁。

基本的Annotation

● @Override——限定重写父类方法
● @Deprecated——标示已过时
● @SuppressWarning——抑制编译器警告
● @SafeVarargs——这货与Java7里面的堆污染有关


JDK的元Annotation,元注解

JDK除了提供上述的几种基本的Annotation外,还提供了几种Annotation,用于修饰其他的Annotation定义

1. @Retention 这个是决定你Annotation存活的时间的,它包含一个RetationPolicy的value成员变量,用于指定它所修饰的Annotation保留时间,一般有:

○ Retationpolicy.CLASS:编译器将把Annotation记录在Class文件中,不过当java程序执行的时候,JVM将抛弃它。

○ Retationpolicy.SOURCE : Annotation只保留在原代码中,当编译器编译的时候就会抛弃它。

○ Retationpolicy.RUNTIME : 在Retationpolicy.CLASS的基础上,JVM执行的时候也不会抛弃它,所以我们一般在程序中可以通过反射来获得这个注解,然后进行处理。

2. @Target 这个注解一般用来指定被修饰的Annotation修饰哪些元素,这个注解也包含一个value变量:

○ ElementType.ANNOTATION_TYPE : 指定该Annotation只能修饰Annotation。

○ ElementType.CONSTRUCTOR: 指定只能修饰构造器。

○ ElementType.FIELD: 指定只能成员变量。

○ ElementType.LOCAL_VARIABLE: 指定只能修饰局部变量。

○ ElementType.METHOD: 指定只能修饰方法。

○ ElementType.PACKAGE: 指定只能修饰包定义。

○ ElementType.PARAMETER: 指定只能修饰参数。

○ ElementType.TYPE: 指定可以修饰类,接口,枚举定义。

3. @Document  这个注解修饰的Annotation类可以被javadoc工具提取成文档

4. @Inherited  被他修饰的Annotation具有继承性


例子

自定义注解MyAnnotation

@Retention(RetentionPolicy.RUNTIME)//运行时
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})//范围类接口,方法,变量
//@Deprecated //标记过时
@Inherited //注解可被继承
public @interface MyAnnotation {
String value();//只有一个方法是用value()
}


自定义注解MyAnnotation2

@Retention(RetentionPolicy.RUNTIME)//运行时
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})//范围类接口,方法,变量
//@Deprecated //标记过时
@Inherited //注解可被继承
public @interface MyAnnotation2 {
String name2();
int age2();
}


在实例中使用

@MyAnnotation("类注解")
public class User {

@Deprecated
private String userName;

@Deprecated
public void fun() {
//已过时
}

@MyAnnotation("fun2方法注解")
public void fun2(){

}
@MyAnnotation2(name2 = "Coco",age2 = 22)
public void fun3(){

}

}


测试

public static void main(String[] args) {
try {
//得到user字节码
Class c = Class.forName("com.bwie.reflectdemo1.User");
//通过反射得到fun3
Method method = c.getMethod("fun3", null);
//得到fun3上的注解
MyAnnotation2 myAnnotation2 = method.getAnnotation(MyAnnotation2.class);
//打印结果
System.out.println(myAnnotation2.name2()+"--fun3上的注解(多值)--"+myAnnotation2);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}


打印结果

Coco--fun3上的注解(多值)--@com.bwie.reflectdemo1.annotation.MyAnnotation2(name2=Coco, age2=22)


例子2

* 绑定控件,绑定布局,绑定点击事件*

MainActivity

/**
* 1.自定义类注解和成员变量注解
* 2.绑定主布局
* 3。绑定控件
*/
@ContentView(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
@BindView(R.id.tv)
TextView textView;
/*@BindView(R.id.btn)
Button button;*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
InjectUtils.inject(this);
System.out.println(textView);
textView.setText("++++++++++++++++");

}
@MClick({R.id.btn})
public void click(View view) {
Toast.makeText(this, "点击了", Toast.LENGTH_SHORT).show();
}
}


绑定控件

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Inherited
public @interface BindView {
int value();
}


绑定布局

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
public @interface ContentView {
int value();
}


绑定点击事件

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MClick {
int[] value();
}


工具类(通过反射操作相关逻辑)

public class InjectUtils {
/**
* 注入activity,通过反射运行相关逻辑
*/
public static void inject(Activity activity) {
injectContentView(activity);
injectBindView(activity);
injectBindOnClick(activity);
}

//绑定点击事件
private static void injectBindOnClick(final Activity activity) {
Class c = activity.getClass();
Method[] methods = c.getDeclaredMethods();
for (final Method method : methods) {
method.setAccessible(true);
MClick annotation = method.getAnnotation(MClick.class);
if (annotation != null) {
int[] value = annotation.value();
for (int i : value) {
int id = i;
final View btn = activity.findViewById(id);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
method.invoke(activity,btn);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Log.d(TAG, "onClick: "+1);
}
});
}
}

}
}

//注入contentview
private static void injectBindView(Activity activity) {
//得到activity字节码
Class clazz = activity.getClass();
Field[] fields = clazz.getDeclaredFields();
if (fields != null && fields.length > 0) {
for (Field field : fields) {
//设置权限
field.setAccessible(true);
//得到成员变量的注解
BindView bindView = field.getAnnotation(BindView.class);
if (bindView != null) {
//注释的值
int value = bindView.value();
//得到每个id的view
View view = activity.findViewById(value);
try {
field.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}

}
}
}

}

/**
* 绑定contentview,实现其逻辑
*/
private static void injectContentView(Activity activity) {

//得到Activity字节码
Class clazz = activity.getClass();
//得到类上面的注解
ContentView contentView = (ContentView) clazz.getAnnotation(ContentView.class);
if (contentView!=null){
int layoutId = contentView.value();

try {
Method method = clazz.getMethod("setContentView", int.class);
method.invoke(activity,layoutId);
} catch (Exception e) {
e.printStackTrace();
}
}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: