泛型
泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。泛型也可以看作是一个变量,用来接收数据类型。
E e:Element 元素
T t:Type 类型
public class ArrayList<E>{ public boolean add(E e){} public E get(int index){} }
创建集合对象的时候,就会确定泛型的数据类型
ArrayList<String> list = new ArrayList<String>();
创建集合对象,不使用泛型:
好处:集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据.
弊端: 不安全,会引发异常.
ArrayList list=new ArrayList();
创建集合对象,使用泛型:
好处:
- 避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
- 把运行期异常(代码运行之后会抛出的异常),提升到了编译期(写代码时候就会报错)
弊端:
泛型是什么类型,只能存储什么类型的数据
ArrayList<String> list = new ArrayList<String>();
含有泛型的类
定义和使用含有泛型的类:
泛型可以接收任意的数据类型,所以在不确定是什么数据类型的时候,可以创建一个泛型的类。
//泛型类的创建: public class GenericClass<E> { private E name; public E getName() { return name; } public void setName(E name) { this.name = name; } }
//泛型类的使用: public class DemoGeneric { public static void main(String[] args) { //不写泛型默认为Object类型 GenericClass gc1 = new GenericClass(); gc1.setName("字符串"); Object obj = gc1.getName(); System.out.println(obj); //创建GenericClass对象,泛型使用Integer类型 GenericClass<Integer> gc2 = new GenericClass<>(); gc2.setName(1); Integer name = gc2.getName(); System.out.println(name); //创建GenericClass对象,泛型使用String类型 GenericClass<String> gc3 = new GenericClass<>(); gc3.setName("小明"); String name1 = gc3.getName(); System.out.println(name1); } }
输出结果:
字符串
1
小明
含有泛型的方法
创建和使用含有泛型的方法:
泛型定义在方法的修饰符和返回值类型之间
格式: 修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){ 方法体; }
含有泛型的方法,在调用方法的时候确定泛型的数据类型,传递什么类型的参数,泛型就是什么类型。
//修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)) public <M> void method01(M m){ System.out.println(m);//方法体 }
public class GenericMethod { //创建含有泛型的方法: public <M> void method01(M m){ System.out.println(m); } //定义一个含有泛型的静态方法 public static <S> void methodStatic(S s){ System.out.println(s); } }
//使用含有泛型的方法: public class DemoGeneric { public static void main(String[] args) { GenericMethod gm = new GenericMethod(); //调用含有泛型的方法method01,传递什么类型,泛型就是什么类型 gm.method01(10); gm.method01("abc"); gm.method01(8.8); gm.method01(true); gm.methodStatic("静态方法,不建议创建对象使用"); GenericMethod.methodStatic("静态方法,通过类名直接使用"); } }
含有泛型的接口
格式: 修饰符 interface接口名<代表泛型的变量>{ }
public interface MyGenericInterface<E>{ }
使用方式:
way1:定义接口的实现类,实现类指定接口的泛型。
way2:接口使用什么泛型,实现类就是用什么泛型,类跟着接口走。(定义一个含有泛型的类,创建对象的时候确定泛型的类型)//定义含有泛型的接口: public interface GenericInterface<I> { public abstract void method(I i); }
//使用way1的实现类:实现类指定接口的泛型 public class GenericInterfaceImpl01 implements GenericInterface<String>{ @Override public void method(String s) { System.out.println(s); } }
//使用way2的实现类:实现类也不指定接口的泛型,等到创建对象时再指定 public class GenericInterfaceImpl02<I> implements GenericInterface<I>{ @Override public void method(I i) { System.out.println(i); } }
//主函数调用 public class DemoMain { public static void main(String[] args) { //way1:实现类中指定了String型,所以此时只能接收字符串 GenericInterfaceImpl01 gi1 = new GenericInterfaceImpl01(); gi1.method("字符串"); //way2:实现类中没指定泛型,创建对象时指定泛型,就可以接收不同种类的数据了 GenericInterfaceImpl02<Integer> gi2 = new GenericInterfaceImpl02<>(); gi2.method(10); GenericInterfaceImpl02<Double> gi3 = new GenericInterfaceImpl02<>(); gi3.method(8.8); } }
泛型的通配符
当使用泛型类或接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身的方法无法使用。
泛型的通配符:
?:代表任意的数据类型
使用方式:
不能创建对象使用,只能作为方法的参数使用public class Demo { public static void main(String[] args) { ArrayList<Integer> list01 = new ArrayList<>(); list01.add(1); list01.add(2); ArrayList<String> list02 = new ArrayList<>(); list02.add("a"); list02.add("b"); printArray(list01); printArray(list02); } /* 定义一个方法,能遍历所有类型的ArrayList集合 由于不知道ArrayList集合使用什么数据类型,可以使用泛型的通配符?来接收数据类型 */ public static void printArray(ArrayList<?> list){//只能作为方法的参数使用 Iterator<?> it = list.iterator();//定义迭代器 while(it.hasNext()) {//使用迭代器进行遍历 System.out.println(it.next()); } } }
通配符高级使用–受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但JAVA的泛型中可以指定一个泛型的上限和下限。(懂啥意思能看明白即可,使用的相对较少)
泛型的上限:
- 格式:
类型名称 <? extends 类 > 对象名称
- 意义:只能接收该类型及其子类
泛型的下限:
- 格式:
类型名称 <? super 类 > 对象名称
- 意义:只能接收该类型及父类
public class DemoGeneric {
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
Collection<String> list2 = new ArrayList<>();
Collection<Number> list3 = new ArrayList<>();
Collection<Object> list4 = new ArrayList<>();
getElement1(list1);
getElement1(list2);//报错
getElement1(list3);
getElement1(list4);//报错
getElement2(list1);//报错
getElement2(list2);//报错
getElement2(list3);
getElement2(list4);
/*
类与类之间的继承关系
Integer extends Number extends Object
String extends Object
*/
}
//泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
private static void getElement1(Collection<? extends Number> coll) {
}
//泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
private static void getElement2(Collection<? super Number> coll) {
}
}