“这是我参与8月更文挑战的第20天,活动详情查看: 8月更文挑战”
泛型
泛型的概念
泛型是一种未知的数据类型,当我们不知道使用什么数据类型时,就可以使用泛型。
泛型也可以看作是变量,用来接收数据类型。
我们常见的有
- E e :Element 表示元素
- T t:Type 表示类型
注意:当我们创建集合对象时,就会确定泛型的数据类型。
使用泛型的好处
我们知道集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升到object类型,当我们取出每一个对像,并且进行相应的操作时,必须采取类型转换。
通过下面的例子我们来体会下使用泛型的好处。
public static void main(String[] args) {
//不使用泛型,这时集合默认的是object类型对象。
ArrayList list = new ArrayList();
list.add("abc");
list.add(1);
//遍历集合
Iterator iterator = list.iterator();
while(iterator.hasNext()){
//此时正常打印
Object next = iterator.next();
System.out.println(next);
//这时,我需要获取字符串的长度,使用String类的length方法
//向下转型
String s = (String)next;
//这时会抛出ClassCastException类型转换异常。
System.out.println(s.length());
}
}
这里我们可以看出,不使用泛型不安全,容易引发异常。
那还有什么好处呢?
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add(1);//error
使用泛型会把在运行期的错误在编译期就能检测出来。
那泛型就没有弊端吗?当然有。使用泛型时就只能在集合中存储同种类型的数据。
泛型的通配符
当使用泛型类或接口时,传递的数据中,泛型的类型不确定,此时可以通过通配符<?>表示,但是一旦使用通配符后,只能使用object类中的方法,集合元素自身方法无法使用。
通配符的基本使用
泛型的通配符:不知道使用什么类型来接收时,此时可以使用?,?表示位置通配符
注意:
- 不能在创建对象时使用。
- 只能作为方法的参数。 来看下面的例子,方便理解。
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
list1.add("abc");
list1.add("def");
ArrayList<Integer> list2 = new ArrayList<Integer>();
list2.add(2);
list2.add(3);
/*
我们要定义一个方法用来遍历任意的类型的集合,
这时我们不知道集合都是什么类型的,那我们就可以使用通配符来作为方法的参数。
*/
Print(list1);
Print(list2);
}
private static void Print(Collection<?> list) {
Iterator<?> iter = list.iterator();
while(iter.hasNext()){
Object next = iter.next();
System.out.println(next);
}
}
通配符的高级使用
在Java的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
- 格式:类型名称
<? super 类>对象名称 - 意义:只能接收该类型及其父类。 泛型的下限:
- 格式:类型名称
<? extends 类>对象名称 - 意义:只能接收该类型及其子类。 同样我们来通过例子说明
public static void main(String[] args) {
//这里有四个类:Integer Number String Object
//Integer的父类时Number,NUmber的父类是Object
//String类的父类是Object
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Number> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
getElement1(list1);//error
getElement1(list2);//error
getElement1(list3);
getElement1(list4);
getElement2(list1);
getElement2(list2);//error
getElement2(list3);
getElement2(list4);//error
}
private static void getElement1(Collection<? super Number> list) {
}
private static void getElement2(Collection<? extends Number> list) {
}
我们看到有的报错,有的不报错,这就是收到了泛型上限和下限的作用。
写在最后
好了,这里带大家了解了泛型,以及泛型的好处和弊端,以及泛型通配符的使用。下篇我们继续深入学习泛型的使用。
以上内容如有不正之处,欢迎掘友们批评指正。