泛型


在JDK 1.5 之前,编译器允许我们向容器插入不同类据的数据。例

/*
* 现在有一批 Apple 
* 需求:对这一批产品核对 id 再出仓
 */
class Apple{
    private static long counter;
    private final long id = counter++;
    public long id(){ return id; }
}
class Orange{}

public static void main(String[] ages){
    List appleList = new ArrayList();
    appleList.add(new Apple);
    appleList.add(new Orange);
    appleList.add(new Apple);
    appleList.add(new Apple);
    for(int i = 0; i < appleList.size(); i++){
        (Apple)appleList.get(i).id();
    }
}

在 appleList 集合中我们不小心加入了 Orange 类型的元素,因为ArrayList存放的中Object类型,在对 appleList 集合做遍历时,通过get(index) 方法返回的元素是Object类型的引用,所以要强转为Apple类型,又对每个元素都去调用了Apple中的 id() 方法,但 Orange 这个元素没有 id() 这个方法,所以程序在遍历到这个元素时会报错

要想让 ArrayList 只保存 Apple 类型,可以声明 ArrayList<Apple> 尖括号里面放的是类型参数,它指定了这个容器可以存放的类型。参数可以有多个,但要看容器是否支持。

这就是泛型,可以在编译期防止将错误的类型存放到容器中。而且从容器中取出时也不用再做类型转换,因为容器知道存储的是什么类型,在调用get()时替我们执行了转型

public static void main(String[] ages){
    List<Apple> appleList = new ArrayList();
    appleList.add(new Apple);
    //appleList.add(new Orange);//提示错误
    appleList.add(new Apple);
    appleList.add(new Apple);
    for(int i = 0; i < appleList.size(); i++){
        (Apple)appleList.get(i).id();
    }
}

还可以兼容向上转型,可以将Apple类型的子类型添加到被指定为Apple对象的容器中

public class Fuji extends Apple{}
public class Gala extends Apple{}

main:
List<Apple> appleList = new ArrayList();
appleList.add(new Apple());
appleList.add(new Apple());
appleList.add(new Apple());
appleList.add(new Fuji());
appleList.add(new Gala());
for (int i = 0; i < appleList.size(); i++) {
            System.out.println(appleList.get(i));
}

/*
Apple@1b6d3586
Apple@4554617c
Apple@74a14482
Fuji@1540e19d
Gala@677327b6
*/

自定义泛型类

泛型类就是一个或多个类型变量的类。

自定义泛型类,类型变量放在类名的后面,用<>尖括括起来。可以有多个

class Pair<T>{
    private T data;
    
    public Pair(){this.data = null;}
    public Pair(T data){ this.data = data; }
    
    public T getData(){ return data; }
    public void setData(T data){ this.data = data; }
}

类型变量使用大写形式,一般使用 E 表示集合的元素类型;K和V分别表示关键字和值;T(U,S)表示任意类型

自定义泛型方法

自定义泛型方法,类型变量放在修饰符的后面,也是用<>尖括括起来。可以有多个

class ArrayAlg{
    public static <T> T getMiddle(T t){
        return t[t.length / 2];
    }
}

main:
String middle = ArrayAlg.<String>getMiddle("John");

在调用泛型方法时,在方法名前的尖括号内放入具体的类型

限定类型

在类中,如果定义了一个泛型对象,那么意义着它可以是任何类的对象。想它去调用指定的方法,但又不能确保这个泛型所属的类是否有这个方法时,可以将泛型限制为实现了有这个方法的接口的类,从而限定泛型类

public static <T> T getMiddle(T t){
        return t.apple();
}

限定后的代码:

public static <T extends Apple> T getMiddle(T t){
        return t.apple();
}

如果在调用方法时,给定的泛型不是实现Apple类,那么会产生编译错误。

也可以有多个限定,限定类型以 & 隔开:<T extends Apple & Minnex>

泛型机制是在编译阶段起作用,只是给编译器参考,在运行阶段没用。虚拟机中没有泛型对象,泛型可以看作是一个类型的占位符

posted @   hello_12153_98  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示