Java注解,反射和泛型

注解

作用和意义

  • 注解又称标注,是Java1.5引入的,注解本身没有任务意义,单独的注解就是一种注释,它需要结合反射,插桩技术才能体验其用处
  • 元注解: 注解上的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface ARouter {
    String path();
    String group() default "";
}
  • @Target 标识的是注解在什么上,比如class,方法,成员变量等
  • @Retention 保留级别,有RUNTIME,CLASS,SOURCE 他们是包含关系,即CLASS包含SOURCE RUNTIME包含SOURCE和CLASS
  • SOURCE: 1:APT保留级别是最好用(生成class之前) .2:IDE语法检查
  • RUNTIME: 反射用(运行时)

反射

一般情况下,我们使用某个类时必定知道它是什么类,用来做什么的,并且能够获得这个类的引用,我们就可以对这个类进行实例化,然后使用它
反射则是一开始并不知道我要初始化的对象是什么,无法使用new来实例化对象,这个时候我们就可以使用jdk提供的反射调用. 就是在运行时,对于任意一个类,都能够知道这个类的属性和方法.对于任一对象,都能够调用它的任一方法,修改其属性.

下面示例(古老方法 自动findViewById)

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
    @IdRes int value();
}
Activity activity;
反射获取成员变量Filed
Class clazz = Class.forName("android.app.Activity");

//获取自己的所有的成员变量,不包括父类
Field[] declaredFields = clazz.getDeclaredFields();

//获取自己和父类的所有的成员变量(不包括private),包括接口
Field[] fields = clazz.getFields();

//获取成员变量名为xxx的成员变量
Field xxxField = clazz.getField("xxx")
//判断xxxField上是否包含了InjectView注解
boolean isInjectView = xxxField.isAnnotationPresent(InjectView.class)
//如果存在这个注解则可以获取
if (isInjectView) {
		//获取InjectView注解
    InjectView injectView = declaredField.getAnnotation(InjectView.class);
    //获取注解上的值
    int id = injectView.value();
    View view = activity.findViewById(id);
    //开始设置值
    xxxField.setAccessible(true);
    xxxField.set(activity,view);
}

当我们对一个泛型类进行反射时,需要得到泛型中的真实数据类型来完成json反序列化的操作时,此时需要通过Type体系来完成.
Type接口包含了一个实现类(Class)和4个实现接口

  • Class
  • TypeVariable: 泛型类型变量
  • GenericArrayType: 当描述的泛型是泛型类数组时 比如:List[], Map[]
  • ParameterizedType: 具体泛型类型
  • WildcardType:通配符泛型

示例(获取泛型里的具体对象)

class Response<T>{
    Type mType;
    public Response(){
        ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();
        mType = type.getActualTypeArguments()[0];  
    }
    public Type getType(){
        return mType;
    }
}
void test(){
//获取type类型:
//方法1:调用此方法会抛错异常,
Type type = new Response<String>().getType();

//方法2:可以获取到type为String.
Type type = new Response<String>(){}.getType();//new Response<String>(){}相当于创建了一个class文件.

//原因: 方法1是直接创建了一个对象,在编译成class之后不会保留泛型类型,全部为Object,而方法2是创建了一个匿名内部类,生成class时会保留原有的泛型签名
class Response2 extends Response<String>{}
//方法2等于是创建了下面Response2类式对象 也就是方法2 也可以写成下面这种写法
Type type = new Response2().getType();
}

泛型

泛型是JDK5引入了,JVM本身是不支持泛型,但是为了向下兼容,Java是一种伪泛型,所以在编译期的时候会对泛型进行擦除,Java在运行时是不存在泛型信息的.

JAVA中的泛型使用分为以下三种情况

//情况一 泛型接口
public interface ILogin<T>{}

//情况二 泛型类
public class Login<T>{}

//情况三 泛型方法
public <T> T getLoginBean(){
	return new Login<T>();
}

泛型怎么擦除

  • 检查泛型的类型,获取目标类型
  • 擦除类型变量,并替换为限定的类型,这里又分三种情况
    • 如果泛型类型的类型变量没有限定也就是只有一个,则最终这个T会变成Object
    • 如果有限定比如 ,则会用XXXBean作为原始的类型
    • 如果有多个限定的话比如 <T extends XBean&YBean>,则以第一个作为原始类型
  • 生成桥接方法以在扩展保持多态(在有实现接口的时候会出现桥接方法,因为接口泛型里的泛型会转为Object,实现接口就得实现接口里的方法,所以会出现一个桥方法 )
  • 泛型擦除后会将泛型信息保留在类的常量池中

泛型好处

  • 代码更健壮,只要编译期没有报错,运行时就不会出现ClassCastException
  • 代码更简洁,很多都不需要强转
  • 代理更灵活,复用性高
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值