注解分类
分为标准注解和元注解
标准注解
- @Override 对覆盖超类中的方法进行标记
- @Deprecated 标记方法将被抛弃。如果某个类成员的提示中出现了个词,就表示这个并不建议使用这个类成员
- @SuppressWarnings 取消特定代码中的警告
元注解
用来注解其他注解,有以下几种
- @Target 注解所修饰的对象范围
- @Inherited 表示注解的内容可以被子类继承
- @Documented 表示这个注解应该被JavaDoc工具记录
- @Retention 注解的保留策略
Target有以下取值范围
ElementType | 能修饰 说明 |
---|---|
TYPE | 类、接口或枚举类型 |
FIELD | 成员变量 |
METHOD | 方法 |
PARAMETER | 参数 |
CONSTRUCTOR | 构造器 |
LOCAL_VARIABLE | 局部变量 |
ANNOTATION_TYPE | 注解 |
PACKAGE | 包 |
Retention 自定义注解的有效范围
- RetentionPolicy.SOURCE: 源码级注解 只在源代码中保留 一般都是用来增加代码的理解性或者帮助代码检查之类的,比如我们的Override;
- RetentionPolicy.CLASS: 编译时注解 默认的选择,能把注解保留到编译后的字节码class文件中,仅仅到字节码文件中,运行时是无法得到的;
- RetentionPolicy.RUNTIME: 运行时注解,注解不仅 能保留到class字节码文件中,还能在运行通过反射获取到,这也是我们最常用的。
注解代替枚举
通过View.VISIBLE的源码,我们可以发现VISIBLE,INVISIBLE和GONE是用注解来实现枚举的作用的
@IntDef({VISIBLE, INVISIBLE, GONE})
@Retention(RetentionPolicy.SOURCE)
public @interface Visibility {}
public static final int VISIBLE = 0x00000000;
public static final int INVISIBLE = 0x00000004;
public static final int GONE = 0x00000008;
Android注解
在android.support.annotation包中也提供了许多资源的注解
name | exp |
---|---|
AnimRes | 动画 |
AnimatorRes | animator资源类型 |
AnyRes | 任何资源类型 |
ArrayRes | 数组资源 |
AttrRes | attr |
BoolRes | bool资源 |
ColorRes | 颜色资源 |
DimenRes | 尺寸资源 |
DrawableRes | 图片资源 |
IdRes | id资源 |
InterpolatorRes | 插值器资源 |
LayoutRes | 布局资源 |
MenuRes | 菜单资源 |
RawRes | raw资源 |
StringRes | 字符资源 |
StyleRes | 风格资源 |
StyleableRes | styleable资源 |
TransitionRes | transition资源类型 |
XmlRes | xml资源 |
资源注解是为了防止我们在使用程序资源的时候,错误传递资源类型给函数,导致程序错误
Null注解
- @NonNull:不能为空
- @Nullable:可以为空
线程注解
- @UiThread
- @BinderThread只在绑定线程上
- @WorkerThread子线程
- @AnyThread任意
其他
- IntDef
- StringDef
- LongDef
- RequiresApi 表示注释的元素只应在给定API级别或更高级别上调用。
- RequiresPermission
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String provider);
@RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public abstract Location getLastKnownLocation(String provider);
- IntRange
private void testDo(@IntRange(from = 1,to = 100)int s){
Log.e("tag","-------->"+s);
}
- Size 表示注释的元素应该具有给定的大小或长度。注意“-1”的意思是“未设置”
- floatRange
可以在google文档中查看
注解处理器
是javac的一个工具,用来扫描和处理注解。就是在编译时期,通过注解生成.java文件。针对运行时,采用反射机制。针对编译时,注解会采用AbstractProcessor处理
1647e53e3d5d3365.jpgStep 1 新增注解类
新建Module来存放注解,取名为annotations
1647def00161e26d.jpg同时新增一个注解类
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
int value();
}
Step 2 编写注解处理器
新建一个java library,命名为apt-processor
1647df7689b1ffaf.jpg里面的build.gradle跟android library的内容有些不一样,同时添加依赖apt-annotations
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':apt-annotations') //implementation替代了之前的compile
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
接着编写注解处理器ClassProcessor,继承自AbstractProcessor
public class ClassProcessor extends AbstractProcessor{
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return super.getSupportedAnnotationTypes();
}
@Override
public SourceVersion getSupportedSourceVersion() {
return super.getSupportedSourceVersion();
}
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
return false;
}
}
- init
初始化。可以得到ProcessingEnviroment,ProcessingEnviroment提供很多有用的工具类Elements, Types 和 Filer - process
可以在这里写扫描、评估和处理注解的代码,生成Java文件 - getSupportedAnnotationTypes
指定这个注解处理器是注册给哪个注解的,这里说明是注解BindView - getSupportedSourceVersion
返回java版本。通常返回SourceVersion.latestSupported
Step 3 注册注解处理器
在processor中添加依赖
implementation 'com.google.auto.service:auto-service:1.0-rc4'
在注解处理器ClassProcessor中添加@AutoService(Processor.class)
Step 4 app依赖
dependencies {
implementation project(':apt-annotation')
annotationProcessor project(':apt-processor')
}
注解处理器只在编译期间用到,处理完后没有作用,
使用apt插件可以减少引入不必要的文件。官方(Android)提供了annotationProcessor来代替android-apt
参考APT,里面写了如何去生成一个java文件,可以通过javapoet工具
反射
Java反射机制是指在运行状态中
对于任意一个类,都能知道这个类的所有属性和方法;
对于任何一个对象,都能够调用它的任何一个方法和属性;
这样动态获取新的以及动态调用对象方法的功能就叫做反射。
1.获取Clas的三种方法
Class c = Class.forName("java.lang.String");
Class c1 = String.Class;
String str = new String();
Class c2 = str.getClass();
2.获取成员变量
Field[] fields = c.getDeclaredFields();
获取字段的修饰符
int fieldValue = field.getModifiers();//如:private、static、final等
与某个具体的修饰符进行比较
Modifier.isStatic(fieldValue)//看此修饰符是否为静态(static)
获取字段的声明类型
field.getType();//返回的是一个class
3.获取类的方法
Method[] methods = c.getDeclaredMethods();
方法 含义
m.getParameterTypes() 获取传入参数类型Class<?>[]
m.getReturnType() 获取方法返回类型Class<?>
c.getDeclaredMethod("方法名",类型.class...) 获取特定的方法
c.getDeclaredConstructors() 获取所有的构造方法
c.getDeclaredConstructor(类型.class...) 获取指定的构造方法
c.getSuperclass() 获取父类Class
c.getInterfaces() 获取实现的接口Class<?>[]
运行时注解,是通过反射获取
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在于此元素,则返回该元素注释指定的注释类型,否则返回为null
@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
String color() default "blue";//为属性指定缺省值
}
private void ResolveClass(String className) {
try {
Class<?> clazz = classLoader.loadClass(className);
Class<?> aClass = classLoader.loadClass(MyAnnotation .class.getName());
System.out.println(clazz.getName());
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation .class);
if(annotation != null) {
System.out.println(annotation.color());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
网友评论