三十四、泛型
作者:互联网
1、概述
1.1 泛型含义
泛型是一种类型参数,专门用来保存类型用的
最早接触泛型是在ArrayList
ArrayList<String> list1 = new ArrayList<>(); // E = String
ArrayList<Integer> list2 = new ArrayList<>(); // E = Integer
ArrayList list3 = new ArrayList<>(); // E = Object
如果没有给泛型变量设定一个类型,默认表示Object。
1.2 使用泛型的好处
不用泛型带来的问题:
集合若不指定泛型,默认就是Object。存储的元素类型自动提升为Object类型。获取元素时得到的都是Object。若要调用特有方法需要转型,给我们编程带来麻烦。
使用泛型带来的好处:
- 将运行时期的 Exception,转移到了编译时期的编译失败。
- 避免了类型强转的麻烦
// 泛型没有指定类型,默认是Object
ArrayList arr = new ArrayList();
arr.add("Hello");
arr.add("World");
arr.add(100);
arr.add(false);
// 集合中的数据就比较混乱,会给获取数据带来麻烦
for (Object o : arr) {
String str = (String)o;
// 当遍历到非String类数据,就会报异常
// java.lang.ClassCastException
System.out.println(str);
}
1.3 注意
- 泛型的代码在运行的时,泛型会被擦除。后面学习反射的饿时候,可以实现在代码运行的过程中添加其他类型的数据到集合
- 泛型里面只能放引用数据类型
2、泛型的定义和使用
泛型,用来灵活的将数据类型应用到不同的类、接口、方法中。将数据类型作为参数进行传递。
2.1 自定义泛型类
使用场景:
当一个类中定义属性的时候,不确定属性具有什么类型时,就可以使用泛型表示该属性的类型
定义格式:
在类型名后面加上一对尖括号,里面定义泛型,一般使用一个英文大写字母表示,如果有多个泛型,使用逗号分隔。
权限修饰符 class 类名<泛型名>{
类型内部,就可以把泛型名当做是某一种类型使用了。
}
public class Student<X,Y>{
X xObj;
}
泛型的确认:
在创建对象的时候,确认泛型类中泛型的数据类型
ArrayList<String> list = new ArrayList<>();
2.2 自定义泛型接口
使用场景:
当定义接口时,内部方法中其参数类型,返回值类型不确定时,就可以使用泛型替代了。
定义格式:
权限修饰符 interface 接口名<泛型名>{
类型内部,就可以把泛型名当做是某一种类型使用了。
}
public interface Collection<E>{
public boolean add(E e);
}
泛型的确认:
-
可以在实现类实现接口时,确认接口中的泛型的类型
public class MyImp1 implements MyGenericInterface<String> { @Override public void add(String e) { // 省略... } @Override public String getE() { return null; } }
-
如果实现类和接口不指定具体的类型,继续使用泛型指定,那就变成含有泛型的类使用
public class MyImp2<E> implements MyGenericInterface<E> { @Override public void add(E e) { // 省略... } @Override public E getE() { return null; } }
/* * 使用 */ public class GenericInterface { public static void main(String[] args) { MyImp2<String> my = new MyImp2<String>(); my.add("aa"); } }
2.3 自定义泛型方法
使用场景:
当定义方法时,方法中参数类型,返回值类型不确定时,就可以使用泛型替代了
定义格式:
可以在方法的返回值类型前,加上泛型
权限修饰符 <泛型名> 返回值类型 方法名(参数列表){
....
}
public interface Collection<E> extends Iterable<E>{
...
<T> T[] toArray(T[] a); //将集合变成数组
}
泛型的指定:
调用含有泛型的方法时,传入的数据其类型就是泛型的类型
3、泛型通配符
当我们对泛型的类型确定不了,而想要表达的可以是任意类型,可以使用泛型通配符给定。符号就是一个问号:? 表示任意类型,用来给泛型指定的一种通配值。
3.1 通配符基本使用
泛型通配符搭配集合使用一般在方法的参数中比较常见
方法中的参数是一个集合,集合如果携带了通配符,要特别注意如下:
- 集合的类型会提升为Object类型
- 方法中的参数是一个集合,集合如果携带了通配符,那么此集合不能进行添加和修改操作,可以删除和获取。
public static void main(String[] args) {
ArrayList<Number> list1 = new ArrayList<>();
ArrayList<Object> list2 = new ArrayList<>();
ArrayList<String> list3 = new ArrayList<>();
ArrayList<Integer> list4 = new ArrayList<>();
// ... 添加数据
useList3(list1);
useList3(list2);
useList3(list3);
useList3(list4);
}
// 方法的参数是一个List , 泛型为通配符 , 那么此参数可以接收任意类型泛型的List集合
public static void useList3(ArrayList<?> list){
// 方法中的参数是一个集合,集合如果携带了通配符 , 集合中的元素默认是Object类型
// Object o = list.get(0);
// 方法中的参数是一个集合,集合如果携带了通配符 , 那么此集合不能进行添加和修改操作 , 可以删除和获取
// list.add(new Object());
// list.add("");
// list.add(10);
// list.set(0 , "");
System.out.println(list);
list.remove(1);
Object o = list.get(1);
}
3.2 受限泛型
介绍:
受限泛型是指,在使用通配符的过程中,对泛型做了约束,给泛型指定类型时,只能是某个类型父类型或者子类型。
- 泛型的下限
<? super 类型>
:只能是某一类型,及其父类型,其他类型不支持
- 泛型的上限
<? extends 类型>
: 只能是某一类型,及其子类型,其他类型不支持
【代码体现】
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<Integer>();
Collection<String> list2 = new ArrayList<String>();
Collection<Number> list3 = new ArrayList<Number>();
Collection<Object> list4 = new ArrayList<Object>();
getElement1(list1);
getElement1(list2);//报错
getElement1(list3);
getElement1(list4);//报错
getElement2(list1);//报错
getElement2(list2);//报错
getElement2(list3);
getElement2(list4);
}
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
泛型没有继承说法案例:
标签:ArrayList,Object,类型,三十四,泛型,new,public 来源: https://www.cnblogs.com/6ovo6/p/14940760.html