泛型T,?,K,V

为什么要使用泛型?

第一是泛化。可以用T代表任意类型Java语言中引入泛型是一个较大的功能增强不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了,这带来了很多好处。
第二是类型安全。泛型的一个主要目标就是提高Java程序的类型安全,使用泛型可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果不用泛型,则必须使用强制类型转换,而强制类型转换不安全,在运行期可能发生ClassCast
Exception异常,如果使用泛型,则会在编译期就能发现该错误。
第三是消除强制类型转换。泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。
第四是向后兼容。支持泛型的Java编译器(例如JDK1.5中的Javac)可以用来编译经过泛型扩充的Java程序(Generics
Java程序),但是现有的没有使用泛型扩充的Java程序仍然可以用这些编译器来编译。

这里的T,?,K,V都是泛型,不特指某个类型,可以通过一些extends,super方式限定类型。

T泛型一般用于类的构造中。

//构造个Test类,T extends Colleciton表面使用构造方法传入的参数必须是Collection或者Collection的子类。
public  class Test <T extends Collection> {
    T t ;
    //获取传入的参数,并赋值给t
    public Test(T t){
        this.t = t;
    }
}

?泛型用于参数传递。

?? extends? super
说明?不指定默认是Object。extends用于表示数据类型是该类的子类或者该类。super用于表示数据类型是该类或者该类的父类。

配合extends用法:

//这里指定传入的List集合的元素必须是Integer的子类或者Integer;
  public static void  get(List<? extends Integer> test){
    }

调用

传入Integer,可以不指定Integer,默认Integer。
在这里插入图片描述
传入String,编译器不让通过
在这里插入图片描述
如果不用extends,super限定类型,那么默认是Object。因为Object是所有对象的父类。

    public static void  get(List<?> test){
    }

调用默认是Object
在这里插入图片描述
也可以传入其他类型,比如Integer
在这里插入图片描述
配合super的用法

//必须是Integer的父类或者Integer
 public static void  get(List<? super Integer> s){
    }

默认是Integer
在这里插入图片描述
可以传入Integer的父类,如Object
在这里插入图片描述
T和?的主要区别就是,T是用于类中的,因为它能当成给类对象进行修饰,用T来指代传入的数据类型。而?不能,他不能以?t的形式出现,它用来限定传入参数的数据类型,而T不能。

K,V用来指定键值对对象的泛型。如HashMap

	//前面的<K,V>用来指定数据类型,后面的<K,V>指代实际的HashMap的键值对的类型。
    public static   <K extends String,V extends Integer>HashMap<K,V> test()  {
        HashMap<String, Integer> stringIntegerHashMap =  new HashMap<>();
            stringIntegerHashMap.put("123",123);
            //由于实际是K,V类型,所以要强制转换。
        return (HashMap<K, V>) stringIntegerHashMap;
    }

接收如下,由于对K,V进行了限制,K是String或String的子类,V是Integer或Integer的子类,于是编译器能自动判别接收的类型。能够以String,Integer的类型接收HashMap。而不是以K,V接收。
在这里插入图片描述

那么可能有人有疑问了,这里的K,V能否用?,?来替代呢?
答案是肯定的,可以。因为?也是用来限定参数数据类型的。那么上面的写法可以用下面的写法来替代。

    public static   HashMap<? extends String,?extends Integer> test()  {
        HashMap<String, Integer> stringIntegerHashMap =  new HashMap<>();
            stringIntegerHashMap.put("123",123);
        return stringIntegerHashMap;
    }

接收如下
在这里插入图片描述

可以看到,明明我实际已经是传递String,Integer类型了,但是接收的时候它还是当做<?extends String,? extends Integer>接收。
直接使用String,Integer接收还需要强制转换如下
在这里插入图片描述
因此,在键值对中的写法,鼓励还是使用K,V代指泛型。
而以List<>的泛型写法如下

    public static <T extends String>ArrayList<T>   test()  {
        return (ArrayList<T>) new ArrayList<String>();
    }

接收如下
在这里插入图片描述
而以?的写法定义和接收如下

    public static ArrayList<? extends String>   test()  {
        return new ArrayList<String>();
    }

接收
在这里插入图片描述
可以看到,T,K,V泛型可以当做是已经确定的了的泛型,只要返回的参数符合其类型,那么编译器就正确识别并接收。而?是不确定的,只有在作为参数接收的时候,编译器能识别,而作为返回值时,编译器无法识别返回值的具体类型,需要进行强制转换。

总结:使用泛型是为了减少类型之间的强制转换,让编译器能够在未编译时就能知道用户的参数定义是否正确,而不是在运行阶段才能发现并运行异常。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值