注解Annotation
注解:在方法、类、字段上加一个 @XXX 来进行 注释 或者 限定(输入输出规则) 或者 注入代码、帮助写一些重复代码等等操作,单独的注解没有意义,但是结合反射、插桩等技术,就有无限可能。
注解声明
所有的注解都默认实现Annotation接口。
注解声明: 在Interface前面加一个@符号,表示注解。
元注解
元注解:给注解使用的注解
重要的有两:@Target({ElementType.TYPE}) 和 @Retention(RetentionPolicy.SOURCE)
1. Target:声明这个注解是用在哪的。方法?类?参数?变量? 有多个那就{ElementType.TYPE,ElementType.FIELD} “,”隔开排列。
2. Retention:注解指定标记注解的存储方式:注解保留级
SOURCE:注解保留在源码上:在编译期能够获取注解与注解声明的类包括类中所有成员信息,一般用于生成额外的辅助类。 -- 例子:APT技术、IDE语法检查
CLASS:注解保留在字节码:在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。-- 例子:字节码增强(在.class文件上编写代码),AspectJ、热修复Roubust
RUNTIME:注解保留在运行时在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。-- 例子:反射
反射
反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和 方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
Java反射机制主要提供了以下功能:
- 在运行时构造任意一个类的对象
- 在运行时获取或者修改任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的方法(属性)
Class
反射始于Class,Class是一个类,封装了当前对象所对应的类的信息。一个类中有类名,属性,方法,构造器等
获得 Class 对象:
1.通过类名获取 类名.class
2.通过对象获取 对象名.getClass()
3.通过全类名获取 Class.forName(全类名) classLoader.loadClass(全类名)
创建实例
通过反射来生成对象主要有两种方式。
1.使用Class对象的newInstance()方法来创建Class对象对应类的实例。
2.先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。(先取到构造函数,在通过构造函数的newInstance()创建)
获取构造器
Constructor 里有一个newInstance()方法,可以创建对象
public T newInstance(Object ... initargs)
成员变量(字段)
获得方法信息的
反射获取泛型真实类型
当我们对一个泛型类进行反射时,需要的到泛型中的真实数据类型,来完成如json反序列化的操作。此时需要通
过 Type 体系来完成。 Type 接口包含了一个实现类(Class)和四个实现接口,他们分别是:
TypeVariable
泛型类型变量。可以泛型上下限等信息;
ParameterizedType
具体的泛型类型,可以获得元数据中泛型签名类型(泛型真实类型)
GenericArrayType
当需要描述的类型是泛型类的数组时,比如List[],Map[],此接口会作为Type的实现。
WildcardType
通配符泛型,获得上下限信息
TypeVariable
ParameterizedType
GenericArrayType
WildcardType
Gson反序列化
Gson 把String转Json的代码:
fromJson()入参有两种,class或者type:
为什么不用class呢,因为泛型在编译的时候回进行类型擦除。也就是对象具体类型就变成Object了,BeseBean<>里的 ParameteBean当成Object处理,无法返回对象了。
用TypeTolen.getType() 能取到具体的type
那为啥要 new TypeTolen<>()+{}呢
{}说明的是这个创建的是一个匿名内部类,没有{}就是一个对象。如果是一个对象,那么 泛型T 还是被擦除了,变成Object了。但是+了{} 就变成声明一个匿名内部类。就 T就变成一个类,擦除以后多了一个class文件,T指向这个文件。 (大概名字)XXX.BaseBean $1.class。这个$1.class就是BaseBean的一个匿名内部类。然后这个匿名内部类里面没有T泛型,就是具体的ParameteBean,不会被擦除
代理
代理可以在运行时创建实现了一组给定接口的新类
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活
中常见的中介。
目的:(1)通过引入代理对象的方式来间接访问目标对象,防止直接访问目标对象给系统带来的不必要复杂性;
(2)通过代理对象对访问进行控制;
代理模式有三种角色:
抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口
真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业
务逻辑在此。
代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附
加自己的操作。将统一的流程控制都放到代理角色中处理!
静态代理
写死的代理。
动态代理
动态代理的实质跟静态代理一样的,最重要的是代理类是通过Proxy.newProxyInstance()来创建的。
例子:
1.自定义注解,自动注入findViewById 2.自动注入getIntent().getStringExtra()来取得.putExtra("name1","AActivty的值")的数据
1.自动填findViewById代码截图
2.自动注入getIntent().getStringExtra()代码截图
3.自动注入setOnclickLinser 实现butterknife效果
改进,上面的写法很笨!!!
Intent传值,是通过Bundle的。put方法里其实是将name,value装到Bundle里
而通过继续查看Bundle.putString(),居然是存到ArrayMap<String, Object> mMap这个Map里的
取也是从Bundle里取的,各种getStringExtra(String name),getIntExtra(String name, int defaultValue)也是从Bundle里取的
通过上面的查看Bundle就是一个ArrayMap<String, Object> 一个key,value存储的Map,所以从bundle里取值自然就是通过key取出Map里的值
优化后的代码
通过上面分析发现,完全没必要用getIntent自带的各种类型的取值,然后一堆if 来判断各种类型,在取出来。可以直接用Bundle里的get(key)取出来
测试代码
源码地址:
此上所有代码均为学习笔记,请勿用于商业
gitee.com/winding2015…