Skip to content

Commit b10f00d

Browse files
committed
add 注解.md
1 parent 080aae2 commit b10f00d

File tree

1 file changed

+161
-4
lines changed

1 file changed

+161
-4
lines changed

Android加强/注解使用.md

Lines changed: 161 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ RxJava详解
1515
###说明
1616
- `Annotation`的声明是通过关键字`@interface`。这个关键字会去继承`Annotation`接口。
1717
- `Annotation`的方法定义是独特的、受限制的。
18-
`Annotation`类型的方法必须声明为无参数、无异常的。这些方法定义了`Annotation`的成员: 方法名代表成员变量名,而方法返回值代表了成员变量的类型。而且方法的返回值类型必须是基本数据类型、`Class`类型、枚举类型、`Annotation`类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用`default`和一个默认的数值来声明成员变量的默认值,`null`不能作为成员变量的默认值,这与我们平时的使用有很大的区别。
18+
`Annotation`类型的方法必须声明为无参数、无异常的。这些方法定义了`Annotation`的成员: 方法名代表成员变量名,而方法返回值代表了成员变量的类型。而且方法的返回值类型必须是基本数据类型、`Class`类型、枚举类型、`Annotation`类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用`default`和一个默认的数值来声明成员变量的默认值,`null`不能作为成员变量的默认值,这与我们平时的使用有很大的区别。
19+
注解如果只有一个默认属性,可直接用`value()`函数。一个属性也没有则表示该`Annotation``Mark Annotation`
20+
1921

2022
例如:
2123
```java
@@ -31,6 +33,12 @@ public @interface UseCase {
3133

3234
`Annotation`一般作为一种辅助途径,应用在软件框架或者工具中。让这些工具类可以根据不同的`Annotation`注解信息来采取不同的处理过程或者改变相应程的行为。
3335

36+
具体可分为如下三类:
37+
38+
- 标记,用于告诉编译器一些信息
39+
- 编译时动态处理,如动态生成代码
40+
- 运行时动态处理,如得到注解信息
41+
3442

3543
###Annotation分类
3644

@@ -54,17 +62,166 @@ public @interface UseCase {
5462
`Annotation`是指用来定义`Annotation``Annotation`
5563

5664
- `@Retention
65+
保留时间,可为`RetentionPolicy.SOURCE(源码时)``RetentionPolicy.CLASS(编译时)``RetentionPolicy.RUNTIME(运行时)`,默认为`CLASS`。如果值为`RetentionPolicy.SOURCE`那大多都是`Mark Annotation`,例如:`Override``Deprecated``Suppress Warnings``SOURCE`表示仅存在于源码中,在`class`文件中不会包含。`CLASS`表示会在`class`文件中存在,但是运行时无法获取。`RUNTIME`表示会在`class`文件中存在,并且在运行时可以通过反射获取。
5766

5867
- `@Target`
59-
68+
用来标记可进行修饰哪些元素,例如`ElementType.TYPE``ElementType.METHOD``ElementType.CONSTRUCTOR``ElementType.FIELD``ElementType.PARAMETER`等,如果未指定则默认为可修饰所有。
6069
- `@Inherited`
61-
70+
子类是否可以继承父类中的该注解。
6271
- `@Documented`
72+
是否会保存到`javadoc`文档中。
73+
74+
###自定义`Annotation`
75+
76+
77+
78+
###`Annotation`解析
79+
80+
81+
当Java源代码被编译时,编译器的一个插件annotation处理器则会处理这些annotation。处理器可以产生报告信息,或者创建附加的Java源文件或资源。如果annotation本身被加上了RententionPolicy的运行时类,则Java编译器则会将annotation的元数据存储到class文件中。然后,Java虚拟机或其他的程序可以查找这些元数据并做相应的处理。
82+
83+
当然除了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。
84+
85+
86+
#####运行时`Annotation`解析
87+
该类是指`@Retention``RUNTIME``Annotation`
88+
该类型的解析其实本质的使用反射。反射执行的效率是很低的
89+
如果不是必要,应当尽量减少反射的使用,因为它会大大拖累你应用的执行效率。
90+
91+
例如`Target``Method`的注解就可以通过`Method`中的如下方法进行解析:
92+
93+
```java
94+
95+
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
96+
...
97+
}
98+
99+
public Annotation[] getAnnotations() {
100+
...
101+
}
102+
103+
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
104+
...
105+
}
106+
```
107+
108+
当然如果`Target``Field``Class`等那就要去使用`Filed``Class`中的方法来解析了。
109+
```java
110+
public static void main(String[] args) {
111+
try {
112+
Class cls = Class.forName("cn.trinea.java.test.annotation.App");
113+
for (Method method : cls.getMethods()) {
114+
MethodInfo methodInfo = method.getAnnotation(
115+
MethodInfo.class);
116+
if (methodInfo != null) {
117+
System.out.println("method name:" + method.getName());
118+
System.out.println("method author:" + methodInfo.author());
119+
System.out.println("method version:" + methodInfo.version());
120+
System.out.println("method date:" + methodInfo.date());
121+
}
122+
}
123+
} catch (ClassNotFoundException e) {
124+
e.printStackTrace();
125+
}
126+
}
127+
```
63128

64-
#####自定义`Annotation`
65129

66130

67131

132+
#####编译时`Annotation`解析
133+
134+
该类值`@Retention``CLASS``Annotation`,由`APT(Annotaion Processing Tool)`自动进行解析。是在编译时注入,所以不会像反射一样影响效率问题。
135+
136+
我们需要做的是:
137+
138+
- 自定义类继承`AbstractProcessor`
139+
- 重写`process`方法
140+
141+
例如:
142+
143+
```java
144+
@SupportedAnnotationTypes({ "cn.trinea.java.test.annotation.MethodInfo" })
145+
public class MethodInfoProcessor extends AbstractProcessor {
146+
147+
@Override
148+
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {
149+
HashMap<String, String> map = new HashMap<String, String>();
150+
for (TypeElement te : annotations) {
151+
for (Element element : env.getElementsAnnotatedWith(te)) {
152+
MethodInfo methodInfo = element.getAnnotation(MethodInfo.class);
153+
map.put(element.getEnclosingElement().toString(), methodInfo.author());
154+
}
155+
}
156+
return false;
157+
}
158+
}
159+
```
160+
SupportedAnnotationTypes 表示这个 Processor 要处理的 Annotation 名字。
161+
process 函数中参数 annotations 表示待处理的 Annotations,参数 env 表示当前或是之前的运行环境
162+
process 函数返回值表示这组 annotations 是否被这个 Processor 接受,如果接受后续子的 rocessor 不会再对这个 Annotations 进行处理
163+
164+
165+
166+
###使用注解提高代码的检查性
167+
168+
`Google`提供了`Support-Annotations library`来支持更多的注解功能。
169+
可以直接在`build.gradle`中添加如下代码:
170+
171+
```
172+
dependencies {
173+
compile 'com.android.support:support-annotations:23.3.0'
174+
}
175+
```
176+
177+
`Android`提供了很多注解来支持在方法、参数和返回值上面使用,例如:
178+
179+
- `@Nullable`
180+
可以为`null`
181+
182+
- `@NonNull`
183+
不能为`null`
184+
- `@StringRes`
185+
`R.string`类型的资源。
186+
- `@DrawableRes`
187+
`Drawable`类型的资源。
188+
- `@ColorRes`
189+
`Color`类型的资源。
190+
- `@InterpolatorRes`
191+
`Interpolatro`类型。
192+
- `@AnyRes`
193+
`R.`类型。
194+
- `@UiThread`
195+
`UI thread`调用。
196+
- `@RequiresPermission`
197+
来验证该方法的调用者所需要有的权限。检查一个列表中的任何一个权限可以使用`anyOf`属性。想要检查一个权限集合
198+
199+
200+
例如:
201+
202+
```java
203+
import android.support.annotation.NonNull;
204+
...
205+
206+
/** Add support for inflating the <fragment> tag. */
207+
@NonNull
208+
@Override
209+
public View onCreateView(String name, @NonNull Context context,
210+
@NonNull AttributeSet attrs) {
211+
...
212+
}
213+
...
214+
```
215+
216+
```java
217+
import android.support.annotation.StringRes;
218+
...
219+
public abstract void setTitle(@StringRes int resId);
220+
...
221+
222+
遇到那种你写了个`setTitle(int resId)`他确给你传`setTitle(R.drawable.xxx)`的选手,用这种方式能很好的去提示下。
223+
```
224+
68225
69226
---
70227

0 commit comments

Comments
 (0)