是种未知的数据类型,当我们不知道使用什么数据类型的时候可以使用泛型,泛型也可以看出是一个变量用来接收数据类型。
E e: Element元素
ArrayList集合在定义的时候不知道集合中都会存储什么类型的数据,所以类型使用泛
型E未知的数据类型。
1.泛型的好处
创建集合对象,不用泛型
好处:
-
默认Object类型,可以存储任意类型的数据
弊端:
-
不安全,可能会导致类型转换异常。ClassCastException
调用子类特有的方法,向下转型 String s=(String)next; System.out.println(s.length());
Integer类型无法转换为String类型
package setclass.Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class TestDemo {
public static void main(String[] args) {
ArrayList list=new ArrayList();
list.add("张三");
list.add(1);
list.add(true);
Iterator it = list.iterator();
while (it.hasNext()){
Object next = it.next();
System.out.println(next);
//调用子类特有的方法,向下转型
String s=(String)next;
System.out.println(s.length());
}
}
}
创建集合对象,使用泛型
好处:
-
避免类型转换异常的麻烦,可以存储设什么类型的数据就取出什么类型
-
将运行期异常提升到编译期类型
弊端:
-
只能存储一种类型
private static void demo2() {
ArrayList<String> list=new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
Iterator<String> it = list.iterator();
while (it.hasNext()){
String next = it.next();
System.out.println(next);
System.out.println(next.length());
}
}
2.定义和使用含有泛型的类
含有泛型的类:
-
泛型类,模拟ArrayList集合
-
泛型可以接受未知的数据类型,创建对象时确定泛型数据类型
package setclass.Genericdemo;
public class GenericClassDemo<E> {//泛型类,模拟ArrayList集合
//泛型可以接受未知的数据类型,创建对象时确定泛型数据类型
private E name;//E 表示未知数据类型
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
测试类:
-
默认Object类型
GenericClassDemo gcd = new GenericClassDemo();
-
泛型使用String类型
GenericClassDemo< String > gc = new GenericClassDemo<>();
-
泛型使用Integer类型
GenericClassDemo< Integer > gc1 = new GenericClassDemo<>();
package setclass.Genericdemo;
public class GenericTestDemo1 {//测试类
public static void main(String[] args) {
//默认Object类型
GenericClassDemo gcd = new GenericClassDemo();
//泛型使用String类型
GenericClassDemo<String> gc = new GenericClassDemo<>();
gc.setName("张三");
System.out.println(gc.getName());
//泛型使用Integer类型
GenericClassDemo<Integer> gc1 = new GenericClassDemo<>();
gc1.setName(100);
System.out.println(gc1.getName());
}
}
3.定义含有泛型的方法
格式:
修饰符 泛型 返回值类型 方法名(参数列表){
方法体
}
传递什么类型的数据,泛型就是什么数据。 也可以定义含有泛型的静态方法。
package setclass.Genericdemo;
public class GenericMethod {//含有泛型的测试方法
public <E> void gcMethod(E e){
System.out.println(e);
}
}
测试:
GenericMethod gc = new GenericMethod();
gc.gcMethod(10);
运行结果:
10
4.含有泛型的接口
一种在实现接口时,确定泛型的类型;
另一种是在创建对象时,确定泛型的类型。
4.1第一种使用方式:定义接口的实现类,实现接口,指定接口的泛型
迭代器接口:
public interface Iterator< E> {
E next();
Scanner类实现了Iterator接口,并指定接口的泛型为String,所以重写的next方法泛型默认就是String
public final class Scanner implements Iterator< String>{
public String next() { }
}
泛型接口:
public interface GenericInterface<I> { //定义泛型接口
void method(I i);//抽象方法 method,默认public abstract
}
通过实现类,实现接口,指定接口的泛型:
public class GenericInterfaceImp1 implements GenericInterface<String>{//定义实现类
//通过实现接口,指定接口的泛型
@Override
public void method(String s) {
System.out.println(s);
}
}
测试类:
public class GenericInterfaceTestDemo {
public static void main(String[] args) {//测试含有泛型的接口
GenericInterfaceImp1 gci1 = new GenericInterfaceImp1();
gci1.method("潜龙");
}
}
潜龙
4.2第二种使用方式:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走
就相当于定义了一一个含有泛型的类,创建对象的时候确定泛型的类型
public interface List< E>{ boolean add(E e); E get(int index); }
ArrList实现List接口:
public class Arraylist< E> implements list< E>{ public boolean add(E e) {} public E get(int index) {} }
接口使用什么泛型,实现类就使用什么泛型,类跟着接口走:
public class GenericInterfaceImp2<I> implements GenericInterface<I>{
@Override
public void method(I i) {
System.out.println(i);
}
}
测试类:
public class GenericInterfaceTestDemo {
public static void main(String[] args) {//测试含有泛型的接口
GenericInterfaceImp2<String> gci2 = new GenericInterfaceImp2<>();
gci2.method("张三");
GenericInterfaceImp2<Integer> gci21 = new GenericInterfaceImp2<>();
gci21.method(123);
}
}
运行结果:
潜龙
张三
123
5.泛型的通配符
泛型的通配符:
?:代表任意的数据类型
使用方式:
-
不能创建对象使用
-
只能作为方法的参数使用
遍历含有多个数据类型的集合时,用含有泛型通配符的参数的方法遍历,使用迭代器遍历,迭代器返回的为Object类型的数据。
-
泛型没有继承概念。
package setclass.Genericdemo;
import java.util.ArrayList;
import java.util.Iterator;
public class Demo1Generic {//泛型通配符
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
ArrayList<String> list2=new ArrayList<>();
list2.add("zhangsan");
list2.add("刘四");
list2.add("张三");
printArray(list1);
printArray(list2);
}
public static void printArray(ArrayList<?> list){
Iterator<?> it = list.iterator();
while (it.hasNext()){
Object next = it.next();
System.out.println(next);
}
}
}
运行结果:
1
2
3
4
zhangsan
刘四
张三
泛型通配符高级使用
-
泛型的上限限定: ? extends E
代表使用的泛型只能是E类型的子类/本身
-
泛型的下限限定: ? super E
代表使用的泛型只能是E类型的父类/本身
通过extends限制了通配符的上边界,也就是只接受Number及其子类类型。接口的实现和类的集成都可以通过extends来表示。
而这里的Number也可以替换为T,表示该通配符所代表的类型是T类型的子类。
public static void getData(List<? extends T> data) {
System.out.println("data :" + data.get(0));
}
与上界通配符示对照也有下界通配符:
public static void getData(List<? super Integer> data) {
System.out.println("data :" + data.get(0));
}
下界通配符表示该通配符所代表的类型是T类型的父类。