1、使用泛型的意义?
ArrayList集合类的定义:
————ArrayList底层是使用数组的方式实现List集合的。——>做大量的访问员说或修改元素,它的效率高。
ArrayList集合元素定义的是Object数组。该数组中可以存放任何类型的对象。所以,我们并不清楚集合元素,到底指向的是什么样的对象。所以,在使用集合元素时,会先进行类型转换,再调用方法。这时,如果不清楚集合中存放元素的类型,那么,就很容易抛出java.lang.ClassCastException类型转换异常。
那么能不能规定,集合中只能存放什么类型的元素,从而在使用集合元素时,开发者可以清晰的知道集合元素的类型,因此避免这样的类型转换异常呢?泛型,可以解决这些问题。
2、什么是泛型?
泛型:——>是用来限制集合容器只能存放某种数据类型的。泛型可以省略,如果省略,默认泛型是Object类型。
泛型是在JDK1.5中提出的。语法:集合类类名<元素类型>集合对象名 = new 集合类类名<元素类型>();
声明变量的< >必须与new后面的< >保持一致。
ArrayList<String> strLst = new ArrayList<String>();
ArrayList<String> strLst = new ArrayList<>();//JDK1.7才有的钻石语法
strLst.add(“hello”);
String str = strLst.get(0);
泛型,大家也可以理解为“参数化类型”。也就是,可以将一个类中的某些属性的数据类型、方法参数类型、返回类型,都以变量方式表示。在使用/调用时传入具体的类型。
我们来看一下,集合中是如何规定集合元素类型的
|
注意这个E。这可以看做是参数化的类型,ArrayList中采用泛型化定义之后,中的E表示类型形参,可以接收具体的类型实参,凡是出现E的地方,均表示相同的接受自外部的类型实参。换句话说,在定义ArrayList对象时,规定是什么类型,那么凡是引用类型变量E的地方,就是什么类型。 |
例如:
1 2 3 4 5 6 7 8 | //定义了E参数的类型为String ArrayList<String> list = new ArrayList<String>(); //添加元素时,add方法参数为E变量类型。由于定义list对象时,定义了类型为String,那么add方法形参变量类型就是String类型 list.add("abc"); //编译错误,定义list对象时,泛型为String,只能添加String对象 list.add(new JFrame()); //get方法返回的是E变量类型。由于定义list对象时,定义了类型为String,那么get方法返回的就是String类型 String str = list.get(0); |
集合中解决类型转换异常的思路是:通过对象中泛型的定义,在添加元素时,规定只能添加某个类型的元素。如果添加其他类型的对象,那么编译错误。这样,取集合元素时,当然也只能取出同一类型的对象。这样就避免了类型转换异常。
所以,从在加上泛型定义的集合中取出元素时,无需进行类型转换,直接可以定义泛型变量接收集合元素。同样的两个ArrayList集合,也可以通过不同泛型的定义,从而规定存放集合的元素类型。
1 2 | ArrayList<String> slist = new ArrayList<String>(); //只能存放String对象 ArrayList<Integer> ilist = new ArrayList<Integer>();//只能存放Integer对象 |
我们也可以给一个类或一个接口,定义多个泛型参数。
Map集合定义:集合中的元素是以键值对的形式成对出现的。
键值对(K-V),K-Key,V-Value;
每一个元素在放置到容器中的时候,除了要放置它本身以外,还需要指定它的键是多少;一个容器中的每个元素的键不能重复。
定义Map对象时,我们可以给其中的键对象K,和值对象V,指明具体的类型。那么,凡是引用K类型的属性类型、方法参数,方法返回类型,就必须和定义Map对象时的K类型一致。同样,凡是引用V类型的属性类型、方法参数、方法返回类型,也必须和定义Map对象时的V类型一致。
3、自定义泛型
泛型不限于定义在集合框架,是还有比如需要定义类型参数的类、接口、方法都可以。
集合框架中有一个工具类:Collections。该类中提供了一个sort排序方法,定义如下:
1 2 3 | public class Collections{ public static void sort(List<T> list, Comparator<T> c){……} } |
sort方法在给集合元素排序时,需要由开发者定义排序的规则。这样,要由开发者实现Comparator接口,从而定义集合元素的比较规则。
不过,开发者在实现Comparator接口时,需要指出,是给什么样类型元素定义比较规则。
Comparator接口定义如下:
1 2 3 | public interface Comparator<T> { public int compare(T o1, T o2); } |
开发者在实现接口时,定义了Comparator比较器泛型类型后,compare方法参数的类型,就变成了定义比较器泛型的类型。
1 2 3 4 5 6 7 | new Comparator<Student>(){ public int compare(Student o1, Student o2) { return 0; } }; |
开发者在重写compare()方法时,就可以定义两个Student对象比较的规则了。
接口、类和方法都可以使用泛型去定义。
在具体使用时,可以分为泛型接口、泛型类和泛型方法。
在实际开发中,我们也可以通过泛型的定义,来规范一些属性、方法参数,以及返回类型。
总结:
1、泛型,表示参数化类型。可以将一个类中的某些属性的数据类型、方法参数类型、返回类型,都以变量方式表示。在使用/调用时传入具体的类型。
2、可以给一个类或一个接口,定义一个或多个泛型参数。使用的类型和泛型定义的类型一致。
3、泛型,我们也可以根据业务需要进行自定义。接口、类和方法也都可以使用泛型去定义。
4、泛型的好处:1、省略了强转的代码;2、可以吧运行时的问题提前到编译期。