@@ -16,8 +16,14 @@ RxJava详解
1616- ` Annotation ` 的声明是通过关键字` @interface ` 。这个关键字会去继承` Annotation ` 接口。
1717- ` Annotation ` 的方法定义是独特的、受限制的。
1818 ` Annotation ` 类型的方法必须声明为无参数、无异常的。这些方法定义了` Annotation ` 的成员: 方法名代表成员变量名,而方法返回值代表了成员变量的类型。而且方法的返回值类型必须是基本数据类型、` Class ` 类型、枚举类型、` Annotation ` 类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用` default ` 和一个默认的数值来声明成员变量的默认值,` null ` 不能作为成员变量的默认值,这与我们平时的使用有很大的区别。
19- 注解如果只有一个默认属性,可直接用` value() ` 函数。一个属性也没有则表示该` Annotation ` 为` Mark Annotation ` 。
20-
19+ 注解如果只有一个默认属性,可直接用` value() ` 函数。一个属性也没有则表示该` Annotation ` 为` Mark Annotation ` 。
20+ 例如:
21+ ``` java
22+ public @interface UnitTest {
23+ String value ();
24+ }
25+ ```
26+ 在使用时可以直接使用`@UnitTest("GCD")`,`@UnitTest("GCD"`实际上就是是 @UnitTest(value="GCD)的简单写法。
2127
2228例如:
2329``` java
@@ -31,7 +37,7 @@ public @interface UseCase {
3137
3238###作用
3339
34- ` Annotation ` 一般作为一种辅助途径,应用在软件框架或者工具中。让这些工具类可以根据不同的` Annotation ` 注解信息来采取不同的处理过程或者改变相应程的行为。
40+ ` Annotation ` 一般作为一种辅助途径,应用在软件框架或者工具中。让这些工具类可以根据不同的` Annotation ` 注解信息来采取不同的处理过程或者改变相应程的行为。具有“让编译器进行编译检查的作用”。
3541
3642具体可分为如下三类:
3743
@@ -67,7 +73,27 @@ public @interface UseCase {
6773- ` @Target `
6874 用来标记可进行修饰哪些元素,例如` ElementType.TYPE ` 、` ElementType.METHOD ` 、` ElementType.CONSTRUCTOR ` 、` ElementType.FIELD ` 、` ElementType.PARAMETER ` 等,如果未指定则默认为可修饰所有。
6975- ` @Inherited `
70- 子类是否可以继承父类中的该注解。
76+ 子类是否可以继承父类中的该注解。它所标注的` Annotation ` 将具有继承性。
77+ 例如:
78+ ``` java
79+ java.lang.annotation. Inherited
80+
81+ @Inherited
82+ public @interface MyAnnotation {
83+
84+ }
85+ ```
86+ ``` java
87+ @MyAnnotation
88+ public class MySuperClass { ... }
89+ ```
90+
91+ ``` java
92+ public class MySubClass extends MySuperClass { ... }
93+ ```
94+
95+ 在这个例子中` MySubClass ` 类继承了` @MyAnnotation ` 注解,因为` MySubClass ` 继承了` MySuperClass ` 类,而` MySuperClass ` 类使用了` @MyAnnotation ` 注解。
96+
7197- ` @Documented `
7298 是否会保存到` javadoc ` 文档中。
7399
@@ -129,21 +155,49 @@ public class Generation3List extends Generation2List {
129155
130156###` Annotation ` 解析
131157
132-
133158当Java源代码被编译时,编译器的一个插件annotation处理器则会处理这些annotation。处理器可以产生报告信息,或者创建附加的Java源文件或资源。如果annotation本身被加上了RententionPolicy的运行时类,则Java编译器则会将annotation的元数据存储到class文件中。然后,Java虚拟机或其他的程序可以查找这些元数据并做相应的处理。
134159
135160当然除了annotation处理器可以处理annotation外,我们也可以使用反射自己来处理annotation。Java SE 5有一个名为AnnotatedElement的接口,Java的反射对象类Class,Constructor,Field,Method以及Package都实现了这个接口。这个接口用来表示当前运行在Java虚拟机中的被加上了annotation的程序元素。通过这个接口可以使用反射读取annotation。AnnotatedElement接口可以访问被加上RUNTIME标记的annotation,相应的方法有getAnnotation,getAnnotations,isAnnotationPresent。由于Annotation类型被编译和存储在二进制文件中就像class一样,所以可以像查询普通的Java对象一样查询这些方法返回的Annotation。
136161
137162
138163#####运行时` Annotation ` 解析
164+
139165该类是指` @Retention ` 为` RUNTIME ` 的` Annotation ` 。
140166该类型的解析其实本质的使用反射。反射执行的效率是很低的
141167如果不是必要,应当尽量减少反射的使用,因为它会大大拖累你应用的执行效率。
142168
143- 例如` Target ` 为` Method ` 的注解就可以通过` Method ` 中的如下方法进行解析:
169+ - 类注解
170+
171+ 可以通过` Class ` 、` Method ` 、` Field ` 类来在运行时获取注解。下面是通过` Class ` 类获取注解的示例:
144172
145173``` java
174+ Class aClass = TheClass . class;
175+ Annotation [] annotations = aClass. getAnnotations();
176+
177+ for (Annotation annotation : annotations){
178+ if (annotation instanceof MyAnnotation ){
179+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
180+ System . out. println(" name: " + myAnnotation. name());
181+ System . out. println(" value: " + myAnnotation. value());
182+ }
183+ }
184+ ```
185+ 也可以获取一个制定注解类型:
186+ ``` java
187+ Class aClass = TheClass . class;
188+ Annotation annotation = aClass. getAnnotation(MyAnnotation . class);
189+
190+ if (annotation instanceof MyAnnotation ){
191+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
192+ System . out. println(" name: " + myAnnotation. name());
193+ System . out. println(" value: " + myAnnotation. value());
194+ }
195+ ```
146196
197+
198+ ` JDK ` 提供的主要方法有:
199+
200+ ``` java
147201public < A extends Annotation > A getAnnotation(Class<A > annotationType) {
148202 ...
149203}
@@ -157,41 +211,143 @@ public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
157211}
158212```
159213
160- 当然如果` Target ` 为` Field ` 、` Class ` 等那就要去使用` Filed ` 或` Class ` 中的方法来解析了。
214+ - 方法注解
215+
216+ 下面是一个方法使用注解的例子:
161217``` java
162- public static void main(String [] args) {
163- try {
164- Class cls = Class . forName(" cn.trinea.java.test.annotation.App" );
165- for (Method method : cls. getMethods()) {
166- MethodInfo methodInfo = method. getAnnotation(
167- MethodInfo . class);
168- if (methodInfo != null ) {
169- System . out. println(" method name:" + method. getName());
170- System . out. println(" method author:" + methodInfo. author());
171- System . out. println(" method version:" + methodInfo. version());
172- System . out. println(" method date:" + methodInfo. date());
173- }
174- }
175- } catch (ClassNotFoundException e) {
176- e. printStackTrace();
218+ public class TheClass {
219+ @MyAnnotation (name = " someName" , value = " Hello World" )
220+ public void doSomething (){}
221+ }
222+ ```
223+
224+ 你可以通过如下方式获取方法注解:
225+
226+ ``` java
227+ Method method = ... // obtain method object
228+ Annotation [] annotations = method. getDeclaredAnnotations();
229+
230+ for (Annotation annotation : annotations){
231+ if (annotation instanceof MyAnnotation ){
232+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
233+ System . out. println(" name: " + myAnnotation. name());
234+ System . out. println(" value: " + myAnnotation. value());
177235 }
178236}
179237```
238+ 也可以获取一个指定的方法注解,如下:
239+ ``` java
240+ Method method = ... // obtain method object
241+ Annotation annotation = method. getAnnotation(MyAnnotation . class);
180242
243+ if (annotation instanceof MyAnnotation ){
244+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
245+ System . out. println(" name: " + myAnnotation. name());
246+ System . out. println(" value: " + myAnnotation. value());
247+ }
248+ ```
249+
250+ - 参数注解
251+
252+ 在方法的参数中声明注解,如下:
253+ ``` java
254+ public class TheClass {
255+ public static void doSomethingElse (
256+ @MyAnnotation (name = " aName" , value = " aValue" ) String parameter ){
257+ }
258+ }
259+ ```
260+
261+ 可以通过` Method ` 对象获取到参数的注解,如下:
262+ ``` java
263+ Method method = ... // obtain method object
264+ Annotation [][] parameterAnnotations = method. getParameterAnnotations();
265+ Class [] parameterTypes = method. getParameterTypes();
266+
267+ int i= 0 ;
268+ for (Annotation [] annotations : parameterAnnotations){
269+ Class parameterType = parameterTypes[i++ ];
270+
271+ for (Annotation annotation : annotations){
272+ if (annotation instanceof MyAnnotation ){
273+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
274+ System . out. println(" param: " + parameterType. getName());
275+ System . out. println(" name : " + myAnnotation. name());
276+ System . out. println(" value: " + myAnnotation. value());
277+ }
278+ }
279+ }
280+ ```
281+ 注意,` Method.getParameterAnnotations() ` 方法会返回一个二维的` Annotation ` 数组,包含每个方法参数的一个注解数组。
282+
283+ - 变量注解
284+
285+ 下面是一个变量使用注解的例子:
286+ ``` java
287+ public class TheClass {
288+
289+ @MyAnnotation (name = " someName" , value = " Hello World" )
290+ public String myField = null ;
291+ }
292+ ```
293+
294+ 你可以像下面这样获取变量的注解:
295+ ``` java
296+ Field field = ... // obtain field object
297+ Annotation [] annotations = field. getDeclaredAnnotations();
298+
299+ for (Annotation annotation : annotations){
300+ if (annotation instanceof MyAnnotation ){
301+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
302+ System . out. println(" name: " + myAnnotation. name());
303+ System . out. println(" value: " + myAnnotation. value());
304+ }
305+ }
306+ ```
307+
308+ 当然也可以获取一个指定的变量注解,如下:
309+ ``` java
310+ Field field = ... // obtain method object
311+ Annotation annotation = field. getAnnotation(MyAnnotation . class);
312+
313+ if (annotation instanceof MyAnnotation ){
314+ MyAnnotation myAnnotation = (MyAnnotation ) annotation;
315+ System . out. println(" name: " + myAnnotation. name());
316+ System . out. println(" value: " + myAnnotation. value());
317+ }
318+ ```
181319
182320
183321
184322#####编译时` Annotation ` 解析
185323
324+ 在刚才介绍的运行时注解中,很多人肯定会说使用反射会影响性能,那有没有不影响性能的方式呢?当然有了,那就是编译时注解。在编译时会通过注解标示来动态生成一些类或者` xml ` ,而在运行时,这里注解是没有的,它会依靠动态生成的类来进行操作。所以它就和直接调用方法一样,当然不会有效率影响了。
325+
186326该类值` @Retention ` 为` CLASS ` 的` Annotation ` ,由` APT(Annotaion Processing Tool) ` 自动进行解析。是在编译时注入,所以不会像反射一样影响效率问题。
187327
328+ 根据sun官方的解释,APT(annotation processing tool)是一个命令行工具,它对源代码文件进行检测找出其中的annotation后,使用annotation processors来处理annotation。而annotation processors使用了一套反射API并具备对JSR175规范的支持。
329+
330+ annotation processors处理annotation的基本过程如下:首先,APT运行annotation processors根据提供的源文件中的annotation生成源代码文件和其它的文件(文件具体内容由annotation processors的编写者决定),接着APT将生成的源代码文件和提供的源文件进行编译生成类文件。
331+
332+ 简单的和前面所讲的annotation实例BRFW相比,APT就像一个在编译时处理annotation的javac。而且从sun开发者的blog中看到,java1.6 beta版中已将APT的功能写入到了javac中,这样只要执行带有特定参数的javac就能达到APT的功能。
333+
334+
335+
188336我们需要做的是:
189337
190338- 自定义类继承` AbstractProcessor `
191339- 重写` process ` 方法
192340
193341例如:
194342
343+ ``` java
344+ public class Processor extends AbstractProcessor {
345+ }
346+ ```
347+ 我用` Android Studio ` 死活提示找不到` AbstractProcessor ` 类,但是它明明就在` jdk ` 中。我是这样解决的,新建一个` Moduel ` ,在选择类型时将该` Moduel ` 的类型选为` Java Library ` 。然后在该` Module ` 中创建就好了,完美解决。
348+
349+
350+
195351``` java
196352@SupportedAnnotationTypes ({ " cn.trinea.java.test.annotation.MethodInfo" })
197353public class MethodInfoProcessor extends AbstractProcessor {
0 commit comments