注解 反射

注解分类

分为标准注解和元注解

标准注解

  • @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.jpg

Step 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();
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容