Android框架常用java基础知识:反射,注解,动态代理

Android框架常用java基础知识:反射,注解,动态代理

在学习Android的框架的源码的时候,发现大部分框架中都是有对java机制的灵活应用。常见的反射,代理,动态代理,注解,依赖注入等。
下面是我对这些java常用机制的总结:
关于反射:

    反射是可以在运行时获取类的函数、属性、父类、接口等 Class 内部信息的机制。通过反射还可以在运行期实例化对象,调用方法,通过调用 get/set 方法获取变量的值,(包括私有的方法也可以)。这种机制在框架源码中很常见。 一个比较常见的场景就是编译时对于类的内部信息不可知,必须得到运行时才能获取类的具体信息。比如 ORM 框架,在运行时才能够获取类中的各个属性,然后通过反射的形式获取其属性名和值,存入数据库。
 反射原理:
      编译时,Java 类都会被编译成一个.class 文件,这些 Class 对象承载了这个类型的父类、接口、构造函数、方法、属性等原始信息,这些 class 文件在程序运行时会被 ClassLoader 加载到虚拟机中,程序在运行时,当一个类被加载以后,Java 虚拟机就会在内存中自动产生一个 Class 对象。
Java 中一切都是对象,其中所有类型包括基本类型数组,都有对应的 Class 类的对象。java中可以通过类名里来获取该类的class对象。有个这个class对象,就可以做很多操作了。

java中提供的API:

1  获取Class对象:
// 加载指定的 Class 对象,参数 1 为要加载的类的完整路径 :包名+类名 ( 常用方式 )
public static Class<?> forName (String className)
// 加载指定的 Class 对象,参数 1 为要加载的类的完整路径;
// 参数 2 为是否要初始化该 Class 对象,参数 3 为指定加载该类的 ClassLoader.
public static Class<?> forName (String className, boolean shouldInitialize, ClassLoader classLoader)
注意:在调用 Class.forName()方法时, 没有在编译路径下(classpath)找到对应的类,那么将会抛出 ClassNotFoundException。

2  通过反射构造对象,首先要获取类的 Constructor(构造器)对象,然后通过 Constructor 来创建目标类的对象。
   Constructor<?> constructor = clz.getConstructor(String.class);
   // 设置 Constructor 的 Accessible
   constructor.setAccessible(true);
注意: 通过反射获取到 Constructor、Method、Field 后,在反射调用之前将此 对象的 accessible 标志设置为 true ,以此来提升反射速度。值为 true 则指示反射的对象在使用时 应该取消 Java 语言访问检查 。值为 false 则指示反射的对象应该实施 Java 语言访问检查。

3 反射获取类中函数

// 获取 Class 对象中指定函数名和参数的函数,参数一为函数名,参数 2 为参数类型列表
public Method getDeclaredMethod (String name, Class...<?> parameterTypes)
// 获取该 Class 对象中的所有函数( 不包含从父类继承的函数 )
public Method[] getDeclaredMethods ()
// 获取指定的 Class 对象中的**公有**函数,参数一为函数名,参数 2 为参数类型列表
public Method getMethod (String name, Class...<?> parameterTypes)
// 获取该 Class 对象中的所有**公有**函数 ( 包含从父类和接口类集成下来的函数 )
public Method[] getMethods ()

注意: getDeclaredMethod 和 getDeclaredMethods 包含 private、protected、default、public 的函数,并且通过这两个函数获取到的只是在自身中定义的函数,从父类中集成的函数不能够获取到。而 getMethod 和 getMethods 只包含 public 函数,父类中的公有函数也能够获取到。

4 反射获取类中的属性

// 获取 Class 对象中指定属性名的属性,参数一为属性名
public Method getDeclaredField (String name)
// 获取该 Class 对象中的所有属性( 不包含从父类继承的属性 )
public Method[] getDeclaredFields ()
// 获取指定的 Class 对象中的**公有**属性,参数一为属性名
public Method getField (String name)
// 获取该 Class 对象中的所有**公有**属性 ( 包含从父类和接口类集成下来的公有属性 )
public Method[] getFields ()

5 反射获取指定类型的注解

// 获取指定类型的注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) ;
// 获取 Class 对象中的所有注解
public Annotation[] getAnnotations() ;
关于动态代理:
 

代理类在程序运行前不存在、运行时由程序动态生成的代理方式称为动态代理。

    Java 提供了动态代理的实现方式,可以在运行时刻动态生成代理类。这种代理方式的一大好处是可以方便对代理类的函数做统一或特殊处理,

如记录所有函数执行时间、所有函数执行前添加验证判断、对某个特殊函数进行特殊操作,而不用像静态代理方式那样需要修改每个函数。

实现动态代理包括三步:
(1). 新建委托类;动态代理要求委托类必须实现了某个接口(该类是接口的实现类,接口中是要代理暴露在外的方法)
(2). 实现InvocationHandler接口,这是负责连接代理类和委托类的中间类必须实现的接口;(要重写invoke()方法)
(3). 通过Proxy类新建代理类对象。
主要的内部实现原理:

InvocationHandler是负责连接代理类和委托类的中间类必须实现的接口。

public Object invoke(Object proxy, Method method, Object[] args)

函数需要去实现,参数:
proxy表示 通过 Proxy.newProxyInstance() 生成的代理类对象
method 表示代理对象被调用的函数。
args 表示代理对象被调用的函数的参数。

调用代理对象的每个函数实际最终都是调用了InvocationHandlerinvoke函数。

invoke函数中可以通过对method做一些判断,从而对某些函数特殊处理。

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

loader表示类加载器
interfaces表示委托类的接口,生成代理类时需要实现这些接口
hInvocationHandler实现类对象,负责连接代理类和委托类的中间类

可以这样理解,动态代理实现实际是双层的静态代理,开发者提供了委托类 B,程序动态生成了代理类 A。开发者还需要提供一个实现了InvocationHandler的子类 C,子类 C 连接代理类 A 和委托类 B,它是代理类 A 的委托类,委托类 B 的代理类。用户直接调用代理类 A 的对象,A 将调用转发给委托类 C,委托类 C 再将调用转发给它的委托类 B。

 
 
关于注解:
 
定义:能够添加到 Java 源代码的语法元数据。类、方法、变量、参数、包都可以被注解,可用来将信息元数据与程序元素进行关联。Annotation 中文常译为“注解”。
作用:a. 标记,用于告诉编译器一些信息
            b. 编译时动态处理,如动态生成代码
            c. 运行时动态处理,如得到注解信息
分类:
1 标准 Annotation,Override, Deprecated, SuppressWarnings

标准 Annotation 是指 Java 自带的几个 Annotation,上面三个分别表示重写函数,不鼓励使用(有更好方式、使用有风险或已不在维护),忽略某项 Warning

2 元 Annotation,@Retention, @Target, @Inherited, @Documented
@Documented 是否会保存到 Javadoc 文档中
@Retention 保留时间,可选值 SOURCE(源码时),CLASS(编译时),RUNTIME(运行时),默认为 CLASS,SOURCE 大都为 Mark Annotation,这类 Annotation 大都用来校验,比如 Override, SuppressWarnings
@Target 可以用来修饰哪些程序元素,如 TYPE, METHOD, CONSTRUCTOR, FIELD, PARAMETER 等,未标注则表示可修饰所有
@Inherited 是否可以被继承,默认为 false

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值