Java 泛型简单剖析与使用

Posted 帅次

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 泛型简单剖析与使用相关的知识,希望对你有一定的参考价值。

一、前言

  • 泛化:可以用T代表任意类型,所以许多重要的类,比如集合框架,都已经成为泛型化的了,这带来了很多好处。

  • 类型安全:使用泛型可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果不用泛型,则必须使用强制类型转换,而强制类型转换不安全,在运行期可能发生ClassCast Exception异常,如果使用泛型,则会在编译期就能发现该错误。

  • 消除强制类型转换:泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。

        在android源码当中有很多地方用到了泛型。

二、使用

2.1 Java泛型接口

        把泛型定义在接口,如下:

public interface 接口名<泛型类型> 


2.1.1 定义

        使用场景:网络请求后调用接口传入某个实体类(未知),请求成功后返回该实例。如下:

public interface HttpResponse<T> 
    //请求成功
    void onSuccess(T bean);

    //请求失败
    void onError(String response);

2.1.2 使用

        //HomeBean.class
        new HttpResponse<HomeBean>() 
            ...
        ;
        //BannerBean.class
        new HttpResponse<BannerBean>() 
            ....
        ;

        这个T可以是HomeBean 也可以是BannerBean

2.2 Java泛型类

        把泛型定义在类上,如下:

public class 类名<泛型类型> 

2.2.1 定义

        使用场景:我们用到的地方就更多了。如网络请求返回的data(经常被定义为泛型),如下:

public class ResponseData<T> 
    private int errorCode;
    private String errorMsg;
    private T data;

2.2.2使用

    @GET("banner/json")
    Call<ResponseData<List<HomeBanner>>> homeBannerRetrofit();

    @POST("user/register")
    @FormUrlEncoded
    Call<ResponseData<RegisterData>> registerRetrofit(@FieldMap Map<String,String> map);
    

        这个T可以是List<HomeBanner> 也可以是RegisterData

2.3 Java泛型方法

        把泛型定义在类上,如下:

public <泛型类型> 返回类型 方法名<泛型类型 变量名> 


2.3.1 定义

        使用场景:我们用到的地方就更多了。如网络请求返回的data(经常被定义为泛型),如下:

public class Test 
    
    public <T>T name(T data)
        return data;
    ;

2.3.2 使用

        Test test = new Test();
        HomeBean homeBean = test.name(new HomeBean());
        RegisterData registerData = test.name(new RegisterData());
    

        这个T可以是HomeBean 也可以是RegisterData

2.4 Java泛型擦除及其相关内容

        在编译期间,所有泛型信息都会被擦除掉,在生成的字节码中是不包括泛型中的类型信息的。

2.4.1 ArrayList源码

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable


        这明显就是个泛型类。下面咱们看一组实例:

        List<String> list = new ArrayList<>();
        list.add("abc");
        List<Integer> list1 = new ArrayList<>();
        list1.add(123);
        List<UserBean> list2 = new ArrayList<>();
        list2.add(new UserBean(20,"sc"));

        MLog.e(String.valueOf(list.getClass()));

        MLog.e(String.valueOf(list.getClass() == list1.getClass()));

        MLog.e(String.valueOf(list.getClass() == list2.getClass()));

        MLog.e(String.valueOf(list1.getClass() == list2.getClass()));

        打印结果:

E/---mlog----: class java.util.ArrayList
E/---mlog----: true
E/---mlog----: true
E/---mlog----: true

        然后你会发现ArrayList<E>中的泛型<E>被擦除。所以add的时候全部以Object的形式添加。

2.5 Java泛型通配符

2.5.1 T,E,K,V

约定俗成的东西:

  • T (type) 表示具体的一个java类型

  • K V (key value) 分别代表java键值中的Key Value

  • E (element) 代表Element

        也可以定义为其他字母,但是不推荐,比较你用这几个别人一看就知道什么意思。

2.5.2 <? extends T> 上界通配符

        上界通配符:<? extends T> 表示的是类型的上限就是自身,因此通配的参数化类型可能是T或T的子类。

        代码如下:

    private void test()
//        List<? extends YeYe> listZuZong = new ArrayList<ZuZong>();//报错
        List<? extends YeYe> listYeYe = new ArrayList<YeYe>();
        List<? extends YeYe> listBaBa = new ArrayList<BaBa>();
        List<? extends YeYe> listSuSu = new ArrayList<SuSu>();
        List<? extends YeYe> listZiji = new ArrayList<Ziji>();
    ;
    class ZuZong
    
    class YeYe extends ZuZong
    
    class BaBa extends YeYe
    
    class SuSu extends YeYe
    
    class Ziji extends BaBa
    

2.5.3 <? super T> 上界通配符

        下界通配符:<? super T> 表示的是类型的下限就是自身,因此通配的参数化类型可能是T或T的父类,一直朝上直到Object。

        代码如下:

        List<? super YeYe> listObject = new ArrayList<Object>();
        List<? super YeYe> listZuZong = new ArrayList<ZuZong>();
        List<? super YeYe> listYeYe = new ArrayList<YeYe>();
//        List<? super YeYe> listBaBa = new ArrayList<BaBa>();//报错
//        List<? super YeYe> listSuSu = new ArrayList<SuSu>();//报错
//        List<? super YeYe> listZiji = new ArrayList<Ziji>();//报错

2.5.4 <?> 无界通配符

        无界通配符:任意类型。

代码如下:

        List<?> listObject = new ArrayList<Object>();
        List<?> listZuZong = new ArrayList<ZuZong>();
        List<?> listYeYe = new ArrayList<YeYe>();
        List<?> listBaBa = new ArrayList<BaBa>();
        List<?> listSuSu = new ArrayList<SuSu>();
        List<?> listZiji = new ArrayList<Ziji>();

以上是关于Java 泛型简单剖析与使用的主要内容,如果未能解决你的问题,请参考以下文章

了解上界和下界?在 Java 泛型中

Kotlin 初学者泛型简单剖析与使用

Kotlin 初学者泛型简单剖析与使用

Kotlin 初学者泛型简单剖析与使用

Java泛型使用的简单介绍

Java 泛型泛型用法 ( 泛型编译期擦除 | 上界通配符 <? extends T> | 下界通配符 <? super T> )