-
什么是注解?
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 比如我们常见的@Override和@Deprecated都是注解,注解可以加在类、方法、成员变量等上面,类似于给他们“打标签"。
-
注解怎么定义?
public @interface 注解名{} 看起来和定义接口很相似只是多了一个@符号 接口: public interface 接口名 注解: public @interface 注解名
public @interface myapt{
}
-
注解怎么使用?
现在我们注解已经定义好了,使用的时候直接“@注解名”就可以使用了 比如下面我们可以定义在“类、成员变量、成员方法”上:
现在注解定义好也已经使用了,但是我不想定义到类上和成员方法上,只想定义在成员方法上,如何才能让注解只能定义到方法上,定义到别的地方报错呢? 想要的效果:
这个时候就要使用元注解来限定范围了。
-
元注解
元注解通俗的来说就是定义在注解上的注解,在Java中有四个元注解 @Target @Retention @Documented @Inherited
-
@Target
@Target就是用于描述注解的定义范围,可以限制这个注解定义的元素类型。
参数 | 作用 |
---|---|
ElementType.ANNOTATION_TYPE | 可以应用于注解类型 |
ElementType.CONSTRUCTOR | 可以应用于构造函数 |
ElementType.FIELD | 可以应用于字段或属性 |
ElementType.LOCAL_VARIABLE | 可以应用于局部变量 |
ElementType.METHOD | 可以应用于方法级注解 |
ElementType.PACKAGE | 可以应用于包声明 |
ElementType.PARAMETER | 可以应用于方法的参数 |
ElementType.TYPE | 可以应用于类的任何元素 |
要限制只想定义在成员变量上,所以我们应该使用ElementType.FIELD
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface myapt {
}
-
@Retention
@Retention是用于定义注解的生命周期,也可以理解为存储方式。
参数 | 作用 |
---|---|
RetentionPolicy.SOURCE | 标记的注解仅保留在源级别中,并被编译器忽略 |
RetentionPolicy.CLASS | 标记的注解在编译时由编译器保留,但 Java 虚拟机(JVM)会忽略 |
RetentionPolicy.RUNTIME | 标记的注解由 JVM 保留,因此运行时环境可以使用它 |
下面两个元注解使用不多,暂时不做详解
-
@Documented
@Documented是用于描述生成帮助文档时是否要保留其注解信息。
-
@Inherited
@Inherited是用于描述使被它修饰的注解是否具有继承性。
-
注解元素
上面我们只是定义了一个注解,但是不能传任何信息,只是相当于一个标签,现在我们看看要怎么给注解定义参数:
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface lkx {
String name() default "张三"; //可以使用default定义默认的值
int age();
}
-
注意事项:
- 下面代码需要用到反射,如果还不会的小伙伴可以看我前面几篇文章。
- 因为要用反射拿到注解参数,所以@Retention需要定义为RetentionPolicy.RUNTIME
实现代码:
public class APTTest {
@Target({ElementType.FIELD,ElementType.METHOD}) -----//定义注解只能给谁使用
@Retention(RetentionPolicy.RUNTIME)
public @interface myapt{
String b() default "dvalue"; ----- //默认dvalue
int a();
}
@myapt(age = 18) --------- //可以用来传参
private static int bl1;
@myapt(name = "test2",age = 38)
private static String bl2;
public static void main(String[] args) throws Exception {
APTTest tt = new APTTest();
System.out.println("赋值前: bl1: " + bl1+" bl2: "+bl2);
//拿到类的字节码
Class<Test> testClass = APTTest.class;
//拿到所有成员变量
for (Field declaredField : testClass.getDeclaredFields()) {
//检测成员变量上是否有 "我们定义“”的注解
if (declaredField.isAnnotationPresent(lkx.class)) {
myapt annotation = declaredField.getAnnotation(lkx.class);
//获取到注解中的的值
int tmpa = annotation.a();
String tmpb = annotation.b();
System.out.println("通过for循环拿到类里面的变量 a+ " + tmpa + ", b:"+ b );
//declaredField.set(testClass.newInstance(),age);
//declaredField.set(tt,age);
}
}
}
}
@BindView(R.id.groupChat)
Button mGroupChat;
@BindView(R.id.privateChat)
Button mPrivateChat;
注意: 因为注解是使用反射机制的, 所以会影响 “性能”
启动性能、执行性能
可以看一下
butterknife框架
viewbing的源码