注解与反射(一)

1、注解的定义与场景

1、定义

注解本身没有任何意义,单独的注解就是一种注释,他需要结合其他,如:反射、插装等技术才有意义。

Java注解(Annotation)又称Java标注,是JDK1.5引入的一种注释机制。是元数据的一种形式,提供了关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。

我们通过@interface 来实现一个自定义注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Lich {
    
    int value();
    
    String id();
    
}

我们定义这个注解有两个元素,id 跟value,我们可以给她增加一个默认值 在后边增加一个。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Lich {

    int value() default 1;
    String id() default "努力学习";

}

 

2、元注解

在定义注解时,注解类也能够使用其他注解声明。对注解类型进行注解的注解类,我们称之为meta-annotation(元注解)。声明的注解允许作用于哪些节点使用@Target声明保留级别由@Retention声明。其中保留级别如下:

  • RetentionPolicy.SOURCE 标记的注解仅保留在源级别中,并被编译器忽略。
  • RetentionPolicy.CLASS  标记的注解在编译时由编译器保留,但Java虚拟机会忽略。
  • RetentionPolicy.RUNTIME 标记的注解由JVM保留,因此运行环境可以使用它。

SOURCE<CLASS<RUNTIME,即CLASS包含了SOURCE;RUNTIME包含了SOURCE、CLASS。

以上代码中,@Target,@Retention就是我们的元注解。注解上面的注解。@Target 用来指示我们Lich注解能作用在那个范围上,是类上,还是成员属性上面,类上面等。如果注解没有设定默认值,则需要设置值

@Lich(value=1,id="天天向上")
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

我们可以查看字节码

3、应用场景

  • 源码

APT,在编译期能够获得注解与注解声明的类包括类中所有的成员信息,一般用于生成额外的辅助类。

  • 字节码

字节码增强,在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。((在在字节码中写代码)

  • 运行时

在程序运行期间,通过反射技术动态获取其注解与其元素,从而完成不同的逻辑判断。

4.Android注解语法检查

在Android中,我们需要设计接口以供使用者调用时,如出现需要对入参进行限定,如限定为资源ID、布局ID等类型参数,将参数类型直接给int即可。然而我们也可以利用Android为我们提供的语法检查注解,来辅助进行更为直接的参数类型检查与提示。

参数限制为:图片资源ID。

同时我们也可以利用@Intdef来定义自己的入参类型检查。

    private static final int SUNDAY=0;
    private static final int MONDAY=1;

    @IntDef({SUNDAY,MONDAY})
    @Target({ElementType.FIELD,ElementType.PARAMETER})
    @Retention(RetentionPolicy.SOURCE)
    @interface WekDay{

    }
    

    public static void setCurrentDay(@WekDay int currentDay){

        mCurrentIntDay=currentDay;
    }

@Intdef 语法检查是由IDE来检查

2、反射

一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的,并且能够获得此类的引用。于是我们直接对这个类进行实例化之后对这个类对象进行操作。

反射是一开始并不知道我要初始化的对象是什么,自然也无法使用new关键字来创建对象。这个时候,我们使用JDK提供的反射API进行反射调用。反射就是运行状态中,对任意一个类都能够知道这个类所有的属性和方法;对任意一个对象都能够调用它的任意方法和属性;并能改变它的属性。是Java被视为动态语言的关键。

  •  如何运行

      .java->javac->.class

     采集到所有的注解信息->Element->注解处理程序,这个过程不需要我们去处理,只需要javac去处理就好

注解+反射:自动完成findViewById

新建注解类

/**
 * 版本:1.0
 * 创建日期:2020-05-21 00:04
 * 描述:
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectView {

    @IdRes int value();
}

通过反射,对view进行注入

getFields():获取自己+父类的成员(不包括private)
getDeclaredFields():只能获取自己的成员(不包括父类)
/**
 * 版本:1.0
 * 创建日期:2020-05-20 23:59
 * 描述:
 */
public class InjectUtils {

    public static void injectView(Activity activity){

        Class<? extends Activity>cls=activity.getClass();
        Field[] declaredFields = cls.getDeclaredFields();

        for (Field f:declaredFields) {
            //判断属性是否被InjectView注解声明
            if (f.isAnnotationPresent(InjectView.class)){
               InjectView injectView= f.getAnnotation(InjectView.class);
               int id =injectView.value();
                View view = activity.findViewById(id);
                //反射设置属性的值
                f.setAccessible(true);//设置访问的权限 允许操作private的属性
                try {
                    f.set(activity,view);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }


    }
}

对结果进行验证

public class MainActivity extends AppCompatActivity {

    @InjectView(R.id.tv_hello)
    TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InjectUtils.injectView(this);
        textView.setText("你好哇,同学");
    }
}

反射的一些方法与属性:

3、Type体系

  • TypeVariable  泛型类型变量。可以泛型上下限等信息。
  • ParameterizedType 具体泛型类型,可以获得元数据中泛型签名类型(泛型真是类型)
  • GenericArrayType 当需要描述的类型是泛型类的数组时,比如List[],Map[],此接口会作为Type的实现。
  • WildcardType 通配符泛型,获得上下限信息;

 

TypeVariable

/**
 * 版本:1.0
 * 创建日期:2020-05-21 22:36
 * 描述:
 * TypeVariable 泛型信息在编译时会被转换成一个特定类型,而TypeVariable 就是用来反射JVM编译该泛型信息的
 * TypeVaiable 就是<T>  <C extends Collection>中的变量 T、C本身:它有如下方法
 * Type[] getBounds():获取泛型的上边界,若未明确声明上边界则默认为Object
 * D getGenericDeclaration():获取该声明变量的类型
 * String getName():获取在源码中定义的名字
 * 注意:
 * 类型变量在定义的时候只能用extends进行多边界限定,不能用super;
 * 为什么边界是一个数组 ? 因为类型变量可以通过&进行多个上边界限定,因此上边界有多个
 *
 */
public class TestType<K extends Comparable& Serializable,V> {

    K key;
    V value;

    public static void main(String[] args) throws NoSuchFieldException {
        //获取字段类型
        Field fk =TestType.class.getDeclaredField("key");
        Field fv =TestType.class.getDeclaredField("value");

        TypeVariable keyType= (TypeVariable) fk.getGenericType();
        TypeVariable valueType= (TypeVariable) fv.getGenericType();

        //getName方法
        System.out.println(keyType.getName());
        System.out.println(valueType.getName());
        //getGenericDeclaration方法
        System.out.println(keyType.getGenericDeclaration());
        System.out.println(valueType.getGenericDeclaration());
        //getBounds 方法
        System.out.println("K的上界:");            //有两个
        for (Type type:keyType.getBounds()) {     // interface java.lang.Comparable
                                                   // interface java.io.Serializable
            System.out.println(type);
        }
        
        System.out.println("V的上界");

        for (Type type:valueType.getBounds()) {      //没有明确上界的,默认上界是 Object
            System.out.println(type);              //class java.lang.Object
        }


    }
}

 

ParameterizedType:

/**
 * 版本:1.0
 * 创建日期:2020-05-21 22:57
 * 描述:具体的泛型类型,如 Map<String,String>
 * 有如下方法:
 * <p>
 *     Type getRawType():返回承载该泛型信息的对象,如上面那个Map<String,String> 承载泛型的对象是Map
 *     Type[] getActualTypeArguments() 返回实际泛型类型列表,如上面那个Map<String,String>实际泛型列表中有两个元素 ,都是String
 */
public class TestType {


    Map<String,String> map;

    public static void main(String[] args) throws NoSuchFieldException {

        Field f=TestType.class.getDeclaredField("map");
        System.out.println(f.getGenericType());//java.util.Map<java.lang.String, java.lang.String>
        ParameterizedType pType= (ParameterizedType) f.getGenericType();

        System.out.println(pType.getRawType());//interface java.util.Map

        for (Type type:pType.getActualTypeArguments()
             ) {

            //class java.lang.String
            //class java.lang.String
            System.out.println(type);

        }
    }

}

 

GenericArrayType :

/**
 * 版本:1.0
 * 创建日期:2020-05-21 23:06
 * 描述:GenericArrayTyoe
 * 泛型数组,组成数组的元素中有泛型则实现了该接口:它的组成元素是ParameterizedType 或 TypeVariable类型 ,它只有一个方法
 * <p>
 *Type getGenericComponentType:返回数组的组成对象
 */
public class TestType<T> {

    List<String>[] lists;

    public static void main(String[] args) throws NoSuchFieldException {

        Field f=TestType.class.getDeclaredField("lists");
        GenericArrayType genericArrayType= (GenericArrayType) f.getGenericType();

        System.out.println(genericArrayType.getGenericComponentType());//java.util.List<java.lang.String>
        
    }
    
}

WildcardType :

/**
 * 版本:1.0
 * 创建日期:2020-05-07 07:19
 * 描述: 该接口表示通配符泛型,比如?extends Number 和 ?super Integer 它有如下方法
 * Tyoe[] getUpperBounds():获取泛型变量的上界
 * Type[] getLowerBounds() :获取泛型变量的下界
 * 注意:
 * 现阶段通配符只接受一个上边界或者下边界,返回数组是为了以后的扩展,实际上现在返回的数组的大小是1
 *
 *
 */
public class TestType {


    private List<? extends Number> a;//上限
    private List<? super String> b;//下限

    public static void main(String[] args) throws NoSuchFieldException {

        Field fieldA=TestType.class.getDeclaredField("a");
        Field fieldB=TestType.class.getDeclaredField("b");
        //先拿到类型范围
        ParameterizedType pTypeA= (ParameterizedType) fieldA.getGenericType();
        ParameterizedType pTypeB= (ParameterizedType) fieldB.getGenericType();

        //再从泛型里边拿到通配符

        WildcardType wTypeA= (WildcardType) pTypeA.getActualTypeArguments()[0];
        WildcardType wTypeB= (WildcardType) pTypeB.getActualTypeArguments()[0];

        //方法测试
        System.out.println("测试:"+wTypeA.getUpperBounds()[0]);
       // System.out.println("测试:"+wTypeA.getLowerBounds()[0]);
        System.out.println("测试:"+wTypeB.getLowerBounds()[0]);
        System.out.println("测试:"+wTypeB.getUpperBounds()[0]);
        //看看通配符是什么,发音结果为 ?extends java.lang.Number
        System.out.println(wTypeA);

    }
}

 

 

泛型与反射的结合运用

public class TypeReference<T> {


    Type type;

    T t;

    protected TypeReference() {

        //获得泛型类型
        Type genericsSuperclass=getClass().getGenericSuperclass();
        ParameterizedType parameterizedType= (ParameterizedType) genericsSuperclass;
        //因为泛型可定义多个A<T,E...>所以是个数组
        Type[] actualTypeArguements=parameterizedType.getActualTypeArguments();
        type=actualTypeArguements[0];

    }

    public Type getType(){

        return type;
    }
}

对数据进行解析

public class Deserialize {

    static class Respone<T>{

        T data;
        int code;
        String messge;

        @Override
        public String toString() {
            return "Response{"+
                    "data="+data+
                    ",code="+code+
                    ",message="+messge+"\'"+
                    "}";
        }


        public Respone(T data, int code, String messge) {
            this.data = data;
            this.code = code;
            this.messge = messge;
        }
    }


    static class Data{

        String result;

        public Data(String result) {
            this.result = result;
        }

        @Override
        public String toString() {
            return "Data{"+"result="+result+"}";
        }
    }


    static class ChildTypeRefrence{
        Respone<Data> t;
    }

    public static void main(String[] args) {


        Respone<Data> dataRespone=new Respone<>(new Data("数据"),1,"成功");
        Gson gson=new Gson();
        String json=gson.toJson(dataRespone);
        System.out.println(json);
        System.out.println(dataRespone.toString());
        //反序列化

        /**
         * 有花括号,是代表匿名内部类,创建一个匿名内部类的实例对象
         * 没花括号:创建实例对象
         */
        Type type=new TypeReference<Respone<Data>>(){}.getType();
        Type type1=new TypeToken<Respone<Data>>(){}.getType();

        System.out.println("type是:"+type);

        Respone<Data> respone=gson.fromJson(json,type);

        System.out.println("获取返回来的类:"+respone.data.getClass());



    }
}

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值