您好,欢迎访问代理记账网站
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

Java开发中的泛型

泛型,Java开发过程中非常重要的类型之一,很大程度上避免了程序在编译时的错误。日常开发中常见的集合、包装类及方法中,都有泛型的身影。

什么是泛型

泛型,即参数化类型。

在定义方法时有形式参数,对方法调用时有实际参数。

所谓参数化类型便是将类型由原来具体的类型参数化,类似于方法中的变量参数。此时的类型被定义成了一个参数的形式,称之为类型形式参数,在调用时传入具体的类型。

为什么要使用泛型

泛型可以简化代码,便于多种数据类型执行相同的代码

    public int addInt(int a, int b) {
        return a + b;
    }

    public float addFloat(float a, float b) {
        return a + b;
    }

这里做了 int 及 float 两个不同类型数据的加法,如果还需要 double 类型的加法、long类型的加法等等,那么就需要重新再重载 double 类型的加法、long类型的加法的相关方法。

重载的方法过多,代码冗余,不利于维护。其实这里做的都是同一个功能:加法,泛型可以将执行方法中的形式参数的类型 int、float、、进行参数化,简化代码,从而达到同一方法可供多种数据类型共用的效果。

泛型中的类型在使用时指定,不需要强制类型转换

    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("xiaoMing");
        list.add(1);
        list.add(1.1);

        for (int i = 0; i < list.size(); i++) {
            String name = (String) list.get(i);
            System.out.println("name = " + name);
        }
    }

定义了一个集合 list ,在向集合中添加 string 类型元素后,又添加了 int 类型及 float 类型元素,这里是允许的,因为此时集合 list 的默认类型是 object。

在 for 循环中对集合进行输出时

String name = (String) list.get(i);

上面代码中的取值方式出现了 java.lang.ClassCastException 异常。

可以看出,在编码过程中不易发现此类错误,另外,在对集合中的姓名元素取值使用时需要进行强制类型转换。

泛型类

泛型是为了参数化类型:在没有或不创建新的类型的情况下,通过泛型指定的不同类型来控制形式参数具体限制的类型。

在泛型的使用过程中,操作的数据类型实际上是被指定为一个参数,在个参数化的类型可以在类、接口及方法中使用,分别称为泛型类、泛型接口及泛型方法。

声明语法

用类型变量 T ,并用 <> 括起来,放在类名的后面,用以声明泛型类。

public class Gnericity<T> {
    
    // do something
    
}

类型变量可以是任意的大写字母,常用的有 T、E、K、V等。

使用泛型

public class Gnericity<T> {
    private T data;

    public Gnericity(T data) {
        this.data = data;
    }
}

泛型类允许有多个类型变量

类型变量之间用“,”分隔。

public class GnericityMore<K, V> {
    private K key;
    private V value;

    public GnericityMore(K key, V value) {
        this.key = key;
        this.value = value;
    }
}

泛型接口

声明语法

public interface GnericityInterface<T> {

    public T getData();
    
}

实现泛型接口

未指定泛型实际参数

public class ImpGnericity<T> implements GnericityInterface<T> {
    @Override
    public T getData() {
        return null;
    }
}

类在实例化时,需要指定具体类型。

    public static void main(String[] args) {
        ImpGnericity<String> impGnericity = new ImpGnericity();
    }

指定泛型实际参数

public class ImpGnericityMore implements GnericityInterface<String> {
    @Override
    public String getData() {
        return "string";
    }
}

实例化时与使用普通类一致。

    public static void main(String[] args) {
        ImpGnericityMore impGnericityMore = new ImpGnericityMore();
    }

泛型方法

是在调用方法的时候指明泛型的具体类型,泛型方法可以在任何的场景中使用,包括普通类和泛型类。

泛型类中的普通方法和泛型方法的区别

普通方法

public class Gnericity<T> {
    private T data;

    public Gnericity(T data) {
        this.data = data;
    }
    
    public T getData(){
        return data;
    }
}

getData 方法只是类中的一个普通方法,虽然在方法中使用了泛型,但是其并不是泛型方法。此处的 T 在类创建时已经被声明,当前方法只是将 T 作为一个类型使用。

泛型方法

public class Gnericity<T> {
    private T data;

    public Gnericity(T data) {
        this.data = data;
    }

    public T getData() {
        return data;
    }

    public <T> T getDataGnericity(T data) {
        return data;
    }
}

getDataGnericity 才是一个泛型方法。

在方法的访问修饰符与返回值之间必须要有 < T > 声明,声明后的 T 可以在当前方法的任意位置使用。

在泛型方法中,泛型的数量可以是多个,多个泛型数量之间用“,”分隔。

    public <K, V> V getValue(K key, V value) {
        return value;
    }

限定类型变量

对类型变量的约束。

现需要使用 compareTo 方法对两个泛型变量进行比较,找出其中的最大值:

    public <T> T maxCompare(T a, T b) {
        if (a.compareTo(b) > 0)
            return a;
        else
            return b;
    }

此处是不能使用 compareTo 方法的,应为 T 本身无此方法,如果需要确保 T 有 compareTo 方法,那么必须将 T 限制为实现了 Comparable 的类,如下:

    public <T extends Comparable> T maxCompare(T a, T b) {
        if (a.compareTo(b) > 0)
            return a;
        else
            return b;
    }

此处,T 是绑定类型的子类型,Comparable 是 T 的绑定类型,子类型和绑定类型可以是类,也可以是接口。

如果有多个类型变量,且需要对多个类型变量进行约束时, extends 两端允许出现多个:

<T, V extends Comparable & Serializable>

在限定类型中,至允许出现一个类,且这个类必须是限定列表的第一个。

以上对泛型的限定即可用在泛型方法中,也可以用在泛型类中。


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进