美文网首页
Java-泛型

Java-泛型

作者: 杨0612 | 来源:发表于2020-08-31 17:11 被阅读0次
    关键字:泛型、类型擦除、泛型实现、泛型缺点、泛型运用。
    1.不使用泛型会怎么样?

    例子1,int、String元素都可以放入list中,但在取元素的时候,需要做类型转换,如果类型不匹配,只有在运行时才知道错误,注意如果没有给List定义类型,默认是Object;

        private void test() {
            List list=new ArrayList();
            list.add(1);
            list.add("String");
            int data1= (int) list.get(0);
            String data1= (String) list.get(1);
    }
    

    例子2,Person类的data属性可以存放任意类型的数据,但在get的时候需要做类型转换,如果类型不匹配,只有在运行时才知道错误;

    //定义
    public class Person {    
        private Object data;    
        public void setData(Object data){
            this.data=data;
        }    
        public Object getData(){
            return this.data;
        }
    }
    //调用
            Person person=new Person();
            person.setData("name");
            String name= (String) person.getData();
    

    例子1代码使用泛型,list定义为List<Integer>,只能存放Integer、int类型元素,如果放入其他类型元素,编译器类型检查会不通过,而且在获取元素时,不需要做类型转换,因为编译器已经帮我们实现了类型转换,转换成字节码就能看到。

        private void test() {
           List<Integer> list=new ArrayList();
            list.add(1);
            int data1= list.get(0);
    }
    

    例子2代码使用泛型,定义泛型T

    //定义
    public class Person<T> {
        private T data;
        public void setData(T data){
            this.data=data;
        }
    
        public T getData(){
            return this.data;
        }
    }
    person定义为 Person<String>类型,setData只能传入String类型参数,如果放入其他类型元素,编译器类型检查会不通过,getData也不需要做类型转换,因为编译器已经帮我们实现了类型转换;
    //调用
            Person<String> person=new Person();
            person.setData("name");
            String name=person.getData();
    
    2.泛型的好处

    (1)泛型使得类型参数化,也就是把类型当成参数来使用,更具有扩展性,代码复用。列子2中,分别把Integer、String类型当成参数实例化List、Person,List即可以处理Integer类型,也能处理String,甚至自定义类型,Person同理;
    (2)参数类型一旦确定,如果类型不匹配,在编译期就能发现,降低异常概率;

    3.泛型实现

    泛型最终也是靠Object来保存数据的,定义的泛型编译成class文件时会被擦除,这就是类型擦除。例如,List<Integer>编译时候,会将Integer擦除变成List, Person<String> 最后变成Person。虽然泛型被擦除,泛型信息还是会被保存了下来,保存在class字节码常量池中,在使用了泛型的代码处会生成一个signature签名字段指向常量池地址。

    4.类型擦除优点

    (1)List<Integer>变成List,这样加载到方法区,占内存就会比较小,方法区的压力也就小,而C#的泛型类型在内存中就是真实存在;
    (2)Java1.5之前是使用Object,类型擦除就可以兼容之前的代码;

    5.泛型缺点

    (1)基本数据类型无法作为泛型实参
    如果想在list中放入int类型数据,就必现把list定义成List<Integer>,那么在放入取出数据就会涉及到装箱拆箱,这样会对内存有影响(创建对象),而C#可以用基本数据类型作为泛型实参;Android推出SparseArray来替代key为Integer型的Hashmap,这样可以解决装箱拆箱问题;
    (2)泛型无法用作方法重载
    以下代码编译器会报错,因为类型擦除以后,这两个方法是一样的,而C#则可以;

        private void add(List<Integer> data);
        private void add(List<String> data);
    

    (3)泛型无法当做真实类型
    以下代码编译器会报错(Illegal generic type for instanceof),List<Integer> 不是一个真实类型,类型擦除以后还是List;

        private void add(List<Integer> data){
            if(data instanceof List<Integer>){            
            }
        }
    

    以下代码编译器同样会报错(Type parameter 'T' cannot be instantiated directly),泛型T不是一个真实类型

       private <T>void a(){
           T t=new T();
        }
    

    (4)静态方法无法引用泛型类型
    以下代码编译器会报错(com.yang.memorytest.Person.this' cannot be referenced from a static context),因为泛型类型只有在类实例化的时候才确定,而静态方法可以直接通过类来调用;

    public class Person<T> {    
        public static void a(T data){        
        }
    }
    

    如果静态方法需要使用泛型,可以在方法定义泛型,

    public class Person {    
        public static <T>void a(T data){        
        }
    }
    

    (5)泛型的没有继承关系

    public class Person<T> {
        private T data;   
    }
    //虽然ArrayList是List的子类
     Person<List> person=new Person<ArrayList>();
    
    6.泛型运用-Gson

    Gson提供fromJson方法将json转换成实体。虽然方法定义了<T>,但还是需要传入一个 Class<T>类型的参数,方法才能知道具体转换成什么类型,因为方法定义的T泛型最终会被类型擦除。

    //调用处
    ReadList.BookDetail detail = new Gson().fromJson(object.toString(), ReadList.BookDetail.class);
    
    //源码处
      public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
        Object object = fromJson(json, (Type) classOfT);
        return Primitives.wrap(classOfT).cast(object);
      }
    
    7.泛型运用-数据解析

    通过反射获取实体类型,利用Gson进行解析。
    定义抽象类CommonResultListener<T>,上层实现抽象类,并确定T泛型。CommonResultListener反射获取泛型类型,利用Gson进行解析。

    以下代码,CommonResultListener实现了底层网络请求接口,网络请求成功会回调onSuccess方法,我们通过getActualTypeArguments获取泛型类型,最后通过Gson来解析数据。

    public abstract class CommonResultListener<T> extends ResultListener {
        @Override
        public void onSuccess(ResultSupport resultSupport) {
                Type genericSuperclass = getClass().getGenericSuperclass();
                Type genericityType = ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0];
                try {
                    String data = resultSupport.getModel("data") != null ? resultSupport.getModel("data").toString() : "";
                          T t = (new Gson()).fromJson(data, genericityType);
                        callResultSuccess(t);
                } catch (Exception e) {
                    Log.e(TAG, "call back exception!", e);
                }
        }
    ....
    
    总结

    泛型的好处,代码复用、可扩展性以及降低异常概率;

    以上分析有不对的地方,请指出,互相学习,谢谢哦!

    相关文章

      网友评论

          本文标题:Java-泛型

          本文链接:https://www.haomeiwen.com/subject/zgdusktx.html