注解定义
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 其实注解本身对他们注解的代码并没有直接影响,仅仅像一个段"注释"一样。
注解的创建与简单使用
创建一个注解,如上,创建一个注解,跟我们创建一个类对比:
public @interface Test {
String str();
int num();
}
public class A {
String string;
int number;
}
- 创建注解的关键字是@interface,创建类的关键字是class
- 注解声明一个String类型成员变量方式:
String str();
,而类声明一个String类型成员变量方式:String string;
使用注解:
public @interface Test {
String str() default "sss";//可以给这个成员指定一个默认值
int num();
}
public class A {
@Test(num = 0)
String string;
@Test(str = "",num = 1)
int number;
}
- 看下A类中的成员变量string和int都使用了Test注解,这个注解有两个参数,在使用时需要我们以key-value形式传入,如果注解给了default值,也可以不用传
public @interface Test {
String value();
}
public class A {
@Test("xxx")
String string;
}
- 当只有一个参数时,并且声明为value时,就比较特殊,使用时可以直接@Test("xxx")这样使用。当然一个注解也可以没有参数。
到此为止,以上自己写的注解,还没有任何作用,仅仅像注释一样标在了类中的成员变量上而已,对我们的代码程序还没有丝毫影响,如果想要影响我们的代码,还需要对这些类似注释一样的东西在恰当的时机进行"解读"。
元注解
先了解下什么是元注解:在定义注解时,注解类也能够使用其他的注解声明。作用在注解类型上的注解,我们称之为 元注解。
-
@Documented:将被此注解注释的注解包含在 javadoc 中 ,它代表着这个注解会被javadoc工具提取成文档。
-
@Inherited:表示允许子类继承父类中定义的注解
-
@Retention:表示在什么级别保存该注解信息,可选参数在RetentionPolicy枚举中,它是我们在自定义注解中比较常用的元注解。
-
@Retention(RetentionPolicy.SOURCE) 源码级别,保留在源码阶段,会被编译器忽略。看下使用场景:
-
可给APT使用,在java文件通过javac编译生成.class文件时,javac通过注解处理器可以采集到源码中注解信息,打包到Element中,在注解处理程序(AbstractProcessor的process())中处理解析注解,(在编译期间,注解处理程序由javac调起,先执行注解处理程序,再将java文件编译成class)。其主要用于生成一些辅助类文件。注解处理器对注解的应用有很多,如Glide,EventBus3,Butterknife。
-
IDE语法检查,如使用IndDef注解的注解,可以在IDE中编辑代码时限定我们的入参类型,用于替代枚举。如以下调用addPeople时对入参类型限制为0或者1
public static final int WOMAN = 0; public static final int MAN = 1; @IntDef(value = {MAN,WOMAN}) @Retention(RetentionPolicy.SOURCE) @Target(ElementType.PARAMETER) public @interface People{ } public void addPeople(@People int people) { }
-
-
RetentionPolicy.CLASS,字节码级别,注解在编译时由编译器保留<u>在class文件中</u>,但Java虚拟机会忽略(即无法在运行期反射获取注解)。如:字节码增强(插桩),在字节码中写代码(class文件有自己的数据结构,主要有无符号数和表组成)
-
RetentionPolicy.RUNTIME,运行时,标记的注解由JVM保留,因此运行时环境可以使用它,在程序运行期间,通过反射技术动态获取注解与其元素,如通过注解和反射简单粗暴的实现findViewById功能:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface InjectView { int value(); } public class Inject { public static void inject(Activity activity){ //获取activity的Class对象 Class<? extends Activity> aClass = activity.getClass(); //获取所有的成员变量 Field[] fields = aClass.getDeclaredFields(); for (Field field : fields) { //判断是否被InjectView注解 boolean annotationPresent = field.isAnnotationPresent(InjectView.class); if (annotationPresent) { field.setAccessible(true); //获取注解以及其属性值 InjectView annotation = field.getAnnotation(InjectView.class); int value = annotation.value(); try { //进行findViewById操作 View view = activity.findViewById(value); //给view成员变量设置值 field.set(activity,view); } catch (Exception e) { e.printStackTrace(); } } } } } public class MainActivity extends AppCompatActivity { @InjectView(R.id.button) TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Inject.inject(this); textView.setText("通过注解和反射findViewById"); } }
-
网友评论