目录
1. 什么是泛型
泛型:是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,而这种参数类型可以用在类、方法和接口中,分别被称为泛型类
、泛型方法
、泛型接口
。
注意:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
2. 泛型的优点
之前学习集合中,把泛型去掉依旧能够使用集合,但是遗留一些问题:
1. 不能对加入到集合的数据类型进行约束
ArrayList arrayList = new ArrayList();
//仅仅希望集合中存储Dog对象
arrayList.add(new Dog("小黄"));
arrayList.add(new Dog("大黄"));
arrayList.add(new Dog("小白"));
//但是Cat对象依旧添加
arrayList.add(new Cat("小猫咪"));
2. 对集合进行遍历的时候需要进行类型转换,如果数据量较大,效率会降低。
//遍历
for (Object o : arrayList) {
//向下转型
Object ->Dog
Dog dog = (Dog) o;
System.out.println(dog.getName() + "-" + dog.getAge());
}
那么泛型就能够很好的解决这些问题:
ArrayList<Dog> arrayList = new ArrayList<>();
//后面的<>里的Dog可以省略,甚至后面的<>都可以省略
//仅仅希望集合中存储Dog对象
arrayList.add(new Dog("小黄"));
arrayList.add(new Dog("大黄"));
arrayList.add(new Dog("小白"));
//arrayList.add(new Cat("小猫咪")); 加入了泛型,ArrayList<Dog> ,此时在添加Cat类会报错
for (Dog d: arrayList) {
//不用转换,直接使用Dog类型
System.out.println(d.getName());
}
1. 编译时能够检查添加的元素类型是否和自己规定的一致
2. 减少类型转换的次数,避免了在运行时出现ClassCastException,代码更健壮
3. 泛型的语法
泛型接口 : interface 接口 <T> { } eg : interface List<E>
实例化 : List <String> list = new ArrayList <String> ();
泛型类 : class 类名 <T> { } eg : class ArrayList<E>
实例化 : ArrayList <String> arraylist = new ArrayList <String> ();
泛型方法 : 修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
eg : public <T> T[ ] toArray ( T[ ] a) {
泛型使用注意:
1. T 可以为任意字母(常用 T 表示),不代表值,而是表示类型(引用类型)
2. 给泛型指定了具体类型后,可以传入该类型或其子类类型
3. 如果 List list = new ArrayList (); 默认泛型为 <E> E 是 Object
4. 自定义泛型
4.1 自定义泛型接口
public interface GenericsInteface<T> {
public abstract void add(T t);
}
1. 定义类时确定泛型类型
public class GenericsImp implements GenericsInteface<String> {
@Override
public void add(String s) {
System.out.println("设置了泛型为String类型");
}
}
2. 如果此时还不确定泛型类型
public class GenericsImp<T> implements GenericsInteface<T> {
@Override
public void add(T t) {
System.out.println("没有设置类型");
}
}
那么创建对象时,确定泛型的类型
public class GenericsTest {
public static void main(String[] args) {
GenericsImp<String> generics = new GenericsImp<>();
generics.add("确定类型为String");
}
}
4.2 自定义泛型类
public class GenericsClassDemo<T> {
//t这个成员变量的类型为T,T的类型由外部指定
private T t;
//泛型构造方法形参t的类型也为T,T的类型由外部指定
public GenericsClassDemo(T t) {
this.t = t;
}
//泛型方法getT的返回值类型为T,T的类型由外部指定
public T getT() {
return t;
}
}
在创建对象的时候确定泛型(不是必须传入类型,在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制,此时泛型才会起到限制作用。如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。)
Generic<String> genericString = new Generic<String>("Generics");
那么之前定义的泛型类就相当于下面代码:
public class GenericsClassDemo<String> {
private String t;
public GenericsClassDemo(String t) {
this.t = t;
}
public String getT() {
return t;
}
}
4.3 自定义泛型方法
声明了<T>的方法才是泛型方法
<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
public <T> T genercMethod(T t){
System.out.println(t.getClass());
System.out.println(t);
return t;
}
调用方法时,确定泛型的类型:
public static void main(String[] args) {
GenericsClassDemo<String> genericString = new GenericsClassDemo("Generic");
String str = genericString.genercMethod("hello");//传入String类型,返回String类型
Integer i = genericString.genercMethod(123);//传入Integer类型,返回Integer类型
}
泛型方法随着我们的传入参数类型不同,得到的类型也不同。泛型方法能使方法独立于类而产生变化。
5. 泛型的继承和通配符
1. 泛型不具备继承
2. <?> 支持任意类型
3. <? extends A> 支持A类及其子类 ,规定上限
4. <? super A> 支持A类及其父类, 规定下限
public class Genericity_ {
public static void main(String[] args) {
Object o = new String("xx");
//泛型没有继承性
//List<Object> list = new ArrayList<String>();
//举例说明下面三个方法的使用
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<AA> list3 = new ArrayList<>();
List<BB> list4 = new ArrayList<>();
List<CC> list5 = new ArrayList<>();
//如果是 List<?> c ,可以接受任意的泛型类型
printCollection1(list1);
printCollection1(list2);
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
//List<? extends AA> c: 表示 上限,可以接受 AA 或者 AA 子类
// printCollection2(list1);//×
// printCollection2(list2);//×
printCollection2(list3);//√
printCollection2(list4);//√
printCollection2(list5);//√
//List<? super AA> c: 支持 AA 类以及 AA 类的父类,不限于直接父类
printCollection3(list1);//√
//printCollection3(list2);//×
printCollection3(list3);//√
//printCollection3(list4);//×
//printCollection3(list5);//×
}
// ? extends AA 表示 上限,可以接受 AA 或者 AA 子类
public static void printCollection2(List<? extends AA> c) {
for (Object object : c) {
System.out.println(object);
}
}
//说明: List<?> 表示 任意的泛型类型都可以接受
public static void printCollection1(List<?> c) {
for (Object object : c) { // 通配符,取出时,就是 Object
System.out.println(object);
}
}
// ? super 子类类名 AA:支持 AA 类以及 AA 类的父类,不限于直接父类,
//规定了泛型的下限
public static void printCollection3(List<? super AA> c) {
for (Object object : c) {
System.out.println(object);
}
}
}
class AA {
}
class BB extends AA {
}
class CC extends BB {
}