泛型
泛型的格式
<类型>
注意:一般泛型不能是基本数据类型,而是包装数据类型
泛型的好处
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换
泛型不具备继承性,但是数据具有继承性
泛型类
使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
//当我在编写一个类的时候,如果不确定类型,那么这个类就可以定义为泛型类
//再创建对象的时候确定泛型
public class MyArrayList<E> {//类上的泛型,本类中所有都可以使用
Object[] obj = new Object[10];//创建一个数组
int size;//数组的长度
/*
E : 表示是不确定的类型。该类型在类名后面已经定义过了。
e:形参的名字,变量名
* */
public boolean add(E e){//和<E>一致
obj[size] = e;
size++;
return true;
}
public E get(int index){
return (E)obj[index];//强转
}
@Override
public String toString() {
return Arrays.toString(obj);//数组转成字符串
}
}
public static void main(String[] args) {
/* MyArrayList<String> list = new MyArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
System.out.println(list);*/
MyArrayList<Integer> list2 = new MyArrayList<>();
list2.add(123);
list2.add(456);
list2.add(789);
int i = list2.get(0);
System.out.println(i);
System.out.println(list2);
}
泛型方法
public class ListUtil {
private ListUtil(){}
//类中定义一个静态方法addAll,用来添加多个集合的元素。
/*
* 参数一:集合
* 参数二~最后:要添加的元素
*
* */
public static<E> void addAll(ArrayList<E> list, E e1,E e2,E e3,E e4){
//泛型定义在修饰符后面, E e1,E e2,E e3,E e4指的是要添加的元素
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
}
/* public static<E> void addAll2(ArrayList<E> list, E...e){//E...e添加多个元素(个数不确定)
for (E element : e) {
list.add(element);
}
}*/
}
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ListUtil.addAll(list1, "aaa", "bbb", "ccc", "ddd");
System.out.println(list1);
ArrayList<Integer> list2 = new ArrayList<>();
ListUtil.addAll(list2,1,2,3,4);
System.out.println(list2);
}
泛型接口
在接口的后面添加<>
public class MyArrayList2 implements List<String> {//接口确定泛型,创建对象的时候必须使用此泛型
@Override
public int size() {
return 0;
}
}
public class MyArrayList3<E> implements List<E> {//接口不确定泛型,创建对象的时候必须给出泛型
@Override
public int size() {
return 0;
}
}
public static void main(String[] args) {
/*
泛型接口的两种使用方式:
1.实现类给出具体的类型
2.实现类延续泛型,创建实现类对象时再确定类型
*/
MyArrayList3<String> list = new MyArrayList3<>();
}
泛型通配符
泛型不具备继承性
public static void main(String[] args) {
/*
泛型不具备继承性,但是数据具备继承性
*/
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
//调用method方法
//method(list1);
//method(list2);这里报错的原因是list2的泛型是<Fu>,和method(ArrayList<Ye> list)的泛型不一致,因为泛型不具备继承性
//method(list3);
list1.add(new Ye());//但是呢?数据是具有继承性的
list1.add(new Fu());
list1.add(new Zi());
}
/*
* 此时,泛型里面写的是什么类型,那么只能传递什么类型的数据。
* */
public static void method(ArrayList<Ye> list) {//这里的泛型是<Ye>
}
使用通配符
public static void main(String[] args) {
/*
* 需求:
* 定义一个方法,形参是一个集合,但是集合中的数据类型不确定。
*
* */
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
ArrayList<Student2> list4 = new ArrayList<>();
method(list1);
method(list2);
//method(list3);
//method(list4);
}
/*
* 此时我们就可以使用泛型的通配符:
* ?也表示不确定的类型
* 他可以进行类型的限定
* ? extends E: 表示可以传递E或者E所有的子类类型
* ? super E:表示可以传递E或者E所有的父类类型
*
* 应用场景:
* 1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
* 2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符
* 泛型的通配符:
* 关键点:可以限定类型的范围。
* */
public static void method(ArrayList<? super Fu> list) {//<>这个泛型里面些什么就传递什么数据,e Fu Zi Student都可以,但是只想让<>接收Ye Fu Zi 可继承的;这个时候就可以使用泛型通配符
}
class Ye {
}
class Fu extends Ye {
}
class Zi extends Fu {
}
class Student2{}