💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] ### 泛型的基本概念 java中泛型的引入主要是为了解决两个方面的问题: * 集合类型元素在运行期出现类型装换异常,增加编译时类型的检查, * 解决的时重复代码的编写,能够复用算法。 * 保证**类型安全** 例子: ~~~ ArrayList al = new ArrayList(); al.add("abc"); al.add("124"); al.add("32L"); ~~~ 我们可以向al集合中添加任何类型的数据。当我们在取出数据的时候需要时候类型转换,如: ~~~ String s = (String)al.get(0); String s1 = (String)al.get(1); //在运行期,会报错,类型转换错误 Long l = (Long)al.get(2); ~~~ 由此可以看到,没有泛型的时候,减少了编译时的类型检查,在取出元素时需要程序员对每个元素的类型都了解,否则很可能在运行时出现类型转换的异常。 那么下面我们通过泛型集合来看看他给我们带来的好处。 ~~~ ArrayList<String> al1 = new ArrayList<String>(); al1.add("abc"); al1.add(1); //编译时报错, ~~~ 当我们用String参数类型实例化al1后,我们是不能添加int元素的,否则编译器会报错,通常在IDE编辑器,如eclipse中会有错误标识,与此同时,在取出元素也不需要类型转换. ~~~ string value = al1.get(0); //不需要类型转换 ~~~ 这便是泛型所带来的好处。 ### 泛型的使用 java中的泛型主要使用在类,方法,与接口中。首先,我们来简单的看看在类上的使用: ~~~ class Factory<T>{ private T value; public T getValue() { return value; } public void setValue(T v) { this.value = v; } } ~~~   添加测试方法: ~~~ Factory<String> f = new Factory<String>(); f.setValue("factory in use"); System.out.println(f.getValue()); ~~~   泛型接口的使用: ~~~ interface MyInterface<T,U>{ void show(T t, U u); } class ShowTest implements MyInterface<String,Integer>{ @Override public void show(String t, Integer u) { System.out.println(t); System.out.println(u); } } ~~~ 泛型类型参数作用于类上的时候主要是对多个字段及方法签名之间的类型约束。作用于方法的时候主要是对方法的的多个参数做相应的约束,在这里方法的泛型类型参数不再举例,下面我们主要介绍类型参数的约束。 ### 类型参数约束   我们看一个小例子,如下代码所示: ~~~ public static <T> T get(T t1,T t2) { if(t1.compareTo(t2)>=0);//编译错误 ,the method compareTo(T) is undefined for the type T. return t1; } ~~~ 可以看到编译器报错的信息,对于类型T没有定义compareTo方法,在java中类型需要比较的话需要实现Comparable接口,从而重写该方法。 那么我们做如下修改: ~~~ public static <T extends Comparable> T get(T t1,T t2) { //添加类型限定 if(t1.compareTo(t2)>=0); return t1; } ~~~ 通过限定T extends Comparable 表明,T是实现了Comparable的接口的类型,因此也实现了compareTo方法,因此不会产生编译期错误。 > 类型的多个限定时我们可以使用&来进行分割,并且限定的关键词只能使用extends。与此同时在*接口与类型都存在的情况下,类只能放在第一个,并且只能有一个*,如下所示: ~~~ <T extends Object&Comparable&Serializable> ~~~