培训首页  >  JAVA新闻  >  Java这个特性-泛型,很多人还没用过!
沈阳Java零基础培训班4月火爆招生

Java这个特性-泛型,很多人还没用过!

来源:

沈阳市和平区爱尚职业培训机构

    发表于:2022-05-25 17:09:47   20次浏览
相关标签: JAVA培训   沈阳JAVA培训

泛型是 Java 的特性之一,如果想写出优雅而高扩展性的代码,或是想读得懂一些的源码,泛型是绕不开的槛。本文介绍了什么是泛型、类型擦除的概念及其实现,最后总结了泛型使用的佳实践。

前言


想写一下关于 Java 一些特性的文章,虽然这些特性在平常实现普通业务时不必使用,但如果想写出优雅而高扩展性的代码,或是想读得懂一些的源码,这些特性又是不可避免的。

如果对这些特性不了解,不熟悉特性的应用场景,使用时又因为语法等原因困难重重,很难让人克服惰性去使用它们,所以身边总有一些同事,工作了很多年,却从没有用过 Java 的某些特性,写出的代码总是差那么一点儿感觉。

为了避免几年后自己的代码还是非常 low,我准备从现在开始深入理解一下这些特性。本文先写一下应用场景多的泛型。

泛型是什么


首先来说泛型是什么。泛型的英文是 generic,中文意思是通用的、一类的,结合其应用场景,我理解泛型是一种 通用类型。但我们一般指泛型都是指其实现方式,也就是 将类型参数化

对于 Java 这种强类型语言来说,如果没有泛型的话,处理相同逻辑不同类型的需求会非常麻烦。

如果想写一个对 int 型数据的排序,我们编码为(不是主角,网上随便找的=_=):

 public static void quickSort(int[] data, int start, int end) {
        int key = data[start];
        int i = start;
        int j = end;
        while (i < j) {
            while (data[j] > key && j > i) {
                j--;
            }
            data[i] = data[j];

            while (data[i] < key && i < j) {
                i++;
            }
            data[j] = data[i];
        }
        data[i] = key;

        if (i - 1 > start) {
            quickSort(data, start, i - 1);
        }
        if (i + 1 < end) {
            quickSort(data, i + 1, end);
        }
    }

可是如果需求变了,现在需要实现 int 和 long 两种数据类型的快排,那么我们需要利用 Java 类方法重载功能,复制以上代码,将参数类型改为 double 粘贴一遍。可是,如果还要实现 float、double 甚至字符串、各种类的排序呢,难道每添加一种类型就要复制粘贴一遍代码吗,这样未必太不优雅。

当然我们也可以声明传入参数为 Object,并在比较两个元素大小时,判断元素类型,并使用对应的方法比较。这样,代码就会恶心在类型判断上了。不优雅的范围小了一点,并不能解决问题。

这时,我们考虑使用通用类型(泛型),将快排方法的参数设置为一个通用类型,无论什么样的参数,只要实现了 Comparable 接口,都可以传入并排序。

    public static  void quickSort(T[] data, int start, int end) {
        T key = data[start];
        int i = start;
        int j = end;
        while (i < j) {
            while (data[j].compareTo(key) > 0 && j > i) {
                j--;
            }
            data[i] = data[j];

            while (data[i].compareTo(key) < 0 && i < j) {
                i++;
            }
            data[j] = data[i];
        }
        data[i] = key;

        if (i - 1 > start) {
            quickSort(data, start, i - 1);
        }
        if (i + 1 < end) {
            quickSort(data, i + 1, end);
        }
    }

那么,可以总结一下泛型的应用场景了,当遇到以下场景时,我们可以考虑使用泛型:

  • 当参数类型不明确,可能会扩展为多种时。
  • 想声明参数类型为 Object,并在使用时用 instanceof 判断时。

需要注意,泛型只能Object的子类型,如果需要基本类型,可以使用包装类,至于为什么,会在下文中说明。

使用


然后我们来看一下,泛型怎么用。

声明

泛型的声明使用 <占位符 [,另一个占位符] > 的形式,需要在一个地方同时声明多个占位符时,使用 , 隔开。占位符的格式并无限制,不过一般约定使用单个大写字母,如 T 代表类型(type),E 代表元素*(element)等。虽然没有严格规定,不过为了代码的易读性,好使用前检查一下约定用法。

泛型指代一种参数类型,可以声明在类、方法和接口上。

我们常把泛型声明在类上:

    class Generics<T// 在类名后声明引入泛型类型
        private T field;  // 引入后可以将字段声明为泛型类型

        public T getField() // 类方法内也可以使用泛型类型
            return field;
        }
    }

把泛型声明在方法上时:

    public [static void testMethod(T arg) // 访问限定符[静态方法在 static] 后使用 <占位符> 声明泛型方法后,在参数列表后就可以使用泛型类型了
        // doSomething
    }

最后是在接口中声明泛型,如上面的快排中,我们使用了 Comparable 的泛型接口,与此类似的还有 Searializable Iterable等,其实在接口中声明与在类中声明并没有什么太大区别。

调用

然后是泛型的调用,泛型的调用和普通方法或类的调用没有什么大的区别,如下:

    public static void main(String[] args) {
        String[] strArr = new String[2];
        // 泛型方法的调用跟普通方法相同
  Generics.quickSort(strArr, 030 );

  // 泛型类在调用时需要声明一种类型
        Generics sample = new Generics<>();
        Long field = sample.getField();
    }

    // 泛型接口需要在泛型类里实现
    class GenericsImpl<Timplements Comparable<T{
    @Override
    public int compareTo(T o) {
        return 0;
    }
}

类型擦除


讲泛型不可不提类型擦除,只有明白了类型擦除,才算明白了泛型,也就可以避开使用泛型时的坑。

由来

严格来说,Java的泛型并不是真正的泛型。Java 的泛型是 JDK1.5 之后添加的特性,为了兼容之前版本的代码,其实现引入了类型擦除的概念。

类型擦除指的是:Java 的泛型代码在编译时,由编译器进行类型检查,之后会将其泛型类型擦除掉,只保存原生类型,如 Generics 被擦除后是 Generics,我们常用的 List 被擦除后只剩下 List

接下来的 Java 代码在运行时,使用的还是原生类型,并没有一种新的类型叫 泛型。这样,也就兼容了泛型之前的代码。

如以下代码:

                        

Java这个特性-泛型,很多人还没用过!原创内容,请点击 沈阳JAVA培训

  • Adobe认证
  • Oracle认证
  • 思科认证
  • 微软认证
  • Linux认证
  • 其他
  • 职业技能提升
  • 考证找工作
  • 兴趣爱好
  • 周末班
  • 全日制白班
  • 随到随学

热门课程

  • Java零基础从入门到精通

    询价

  • 沈阳Java软件开发工程师培训课程

    询价

  • java工程师培训零基础入门

    询价

  • java后端开发培训

    询价

  • 沈阳编程零基础就业培训班

    询价