iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java中的纸老虎之泛型
  • 447
分享到

Java中的纸老虎之泛型

2024-04-02 19:04:59 447人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录一. 泛型的定义二. 为什么要用到泛型三. 泛型的写法四. 泛型的使用实例1. 求最大值2. 优化五. 通配符1. 基本写法2. 上界3. 下界六. 泛型的限制泛型,其实算是Ja

泛型,其实算是Java当中比较难的语法了,很多人一开始都对其一知半解,也很害怕阅读带泛型的源码,虽然看起来语法很难,但当你理解后会觉得很简单,其实只是一个纸老虎罢了。下面,我将会用非常简单易懂的方式带你去理解它,相信你在认真看完后会有非常大的收获,从此不会再畏惧它!

在这里插入图片描述

一. 泛型的定义

这里大家可以不必去看网上的有些定义,因为相对于比较学术化,只需记住泛型可以在程序设计中指定某种类型,让程序的设计更加规范化即可

二. 为什么要用到泛型

了解到了泛型是什么后,那我们来讨论讨论为什么要用泛型这个语法,这个语法到底是干什么的?别急,下面,我先给大家举一个例子:


class Stack {
    public Object[] objects;
    public int top;

    public Stack() {
        this.objects =new Object[10];
    }

    public void push(Object obj) {
        objects[this.top++] = obj;
    }

    public Object get() {
        return objects[this.top-1];
    }
}

大家可以看看这是在干什么呢?这是我们自己写了一个栈,然后将栈里的数组类型设置成Object类型,这样的话这个栈里任意类型的数据都可以存放了(Object类是任何类的父类,不管插入什么类型的数据,都可以发生向上转型)

下面,我们来测试一下


public class Test {
    public static void main(String[] args) {
        Stack stack=new Stack();
        stack.push(1);
        stack.push(2);
        stack.push("123");
        String str=(String)stack.get();
    }
}

可以看到,我们可以向自己写的栈里放入整形以及字符串等等任何类型的数据,但注意一下取出数据的时候要进行强制类型转换
以上这样写,可以向栈里存放任何类型的数据,比较通用,其优点也可以变成缺点,正因为太通用了,使代码的规范性降低,看起来比较凌乱,这时候,我们可以考虑使用泛型,这样可以在类中或者Java集合中存放特定的数据(使用Java集合时,一般都要用到泛型,而自定义的类型中可以使用泛型也可以不使用)

三. 泛型的写法

以自定义的类型为例,写法为在类名后面加上尖括号,里面写上一个字母(注意,此处写任何字母都可以,只起到一个标记这个类为泛型类的作用)


class Stack<T>

而在new对象时,以栈里只能存放整形为例,前面的尖括号必须写基本数据类型对应的包装类,而后面的尖括号可以不用写,示例如下:


Stack<Integer> stack = new Stack<>();

补一下Java中的基本数据类型与对应的包装类:

在这里插入图片描述

因此,我们前面写的自定义的栈可以写成以下形式(以存放整形为例):


class Stack<T> {
    public T[] objects;
    public int top;

    public Stack() {
        this.objects = (T[])new Object[10];
    }

    public void push(T obj) {
        objects[this.top++] = obj;
    }

    public T get() {
        return objects[this.top-1];
    }
}
 Stack<Integer> stack = new Stack<>();
        stack.push(1);
        stack.push(2);
        int ret = stack.get();
        System.out.println(ret);

特别注意此处:public Stack() { this.objects = (T[])new Object[10]; }
这里不能写成this.objects=new T[10];
原因:
1. 不能new泛型类型的数组
2. 也可理解为泛型是先检查后编译的,如果new泛型类型的数组的话,编译器检查时并不知道T是什么类型的,因此会报错。而编译的时候才会进行擦除机制,都会将其转换为Object类型
3. 正因为有这个擦除机制,这里才能进行数组整体强制类型转换(一般数组不能整体进行强制类型转换),因为泛型只是在编译的时候起作用,而实际运行时都会被擦除成Object类型,即实际运行时是没有泛型这个概念的,也即实际运行时类型都是一样的,所以T本质上是object类型的,所以此代码等价于不进行强制类型转换!!!
4.而直接指定泛型的代码(不是T) 比如:Stack<Integer>和Stack<Character>都是在运行时直接把尖括号里的类型擦掉了,可以看到直接打印的结果(并没有打印出类型):

在这里插入图片描述

在这里插入图片描述

此处注意多理解理解

在这里插入图片描述

四. 泛型的使用实例

1. 求最大值

以上就是泛型的一个重要知识点了,但光看是不够的,还是得通过例子让大家有一个更为深入的理解,比如,如何写一个泛型类来求数组的最大值呢?
基本的框架大概是这样的:(没看懂的小可爱好好看看上面讲的内容哦)


class AlGorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max < array[i]) {
                max = array[i];
            }
        }
        return max;
    }
}

但是此代码if(max < array[i])会报错,为什么呢?因为将来给T传的值一定是一个引用类型,引用类型不能直接比较大于或者小于的,是要用Comparable或Comparator接口里的方法比较的,因为泛型在编译的时候会被擦除成Object类型,但Object类本身并没有实现ComparableComparator接口,所以我们要控制其不要擦除到Object类,所以要给泛型指定一个边界

具体写法如下:


class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            //max < array[i]
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}


class Algorithm<T extends Comparable<T>>

注意,extends叫做上界,此代码代表的意思为T这个泛型类会擦除到实现了Comparable接口的地方,换句话说,这个T类型一定是实现了Comparable接口的
同理:这个代码public class MyArrayList<E extends Number> { ... }代表E为Number的子类或Number本身
下面让我们来用一下:


 Algorithm<Integer> algorithm1 = new Algorithm<>();
        Integer[] integers = {1,2,13,4,5};
        Integer ret = algorithm1.findMax(integers);
        System.out.println(ret);

运行结果如下:

在这里插入图片描述

成功了!

2. 优化

经过上面的努力,我们已经写出了一个泛型类来求一个数组的最大值了,但是,上面的例子是一个整形数组,那么我们能不能在数组里存放别的类型去比较呢?答案是可以的,但是我们还得去new一个对象,例如:Algorithm<String> algorithm2 = new Algorithm<>();这样很麻烦。但是我们可以将求最大值的方法设置成静态的class Algorithm2 <T>,因为是静态的方法,不需要new对象,所以就没有在new对象时指定泛型的过程了,所以没必要给方法后加尖括号,但是去掉之后,代码又会被错:

在这里插入图片描述

我们可以这样修改:


class Algorithm2 {
    public static<T extends Comparable<T>> T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}

此方法public static<T extends Comparable<T>> T findMax(T[] array){}叫做泛型方法

下面继续带大家来用一下:


public static void main(String[] args) {
        Integer[] integers = {1,2,13,4,5};
        //会根据形参的类型推导出整个泛型的类型参数
        Integer ret = Algorithm2.findMax(integers);
        System.out.println(ret);
        Integer ret2 = Algorithm2.<Integer>findMax(integers);
        System.out.println(ret2);
    }

注意,ret1写法和ret2写法是一样的,都可以
打印结果如下:

在这里插入图片描述

五. 通配符

1. 基本写法

通配符也是泛型的一种,下面我们来写一个泛型方法来打印集合中的元素


class Test {

    public static<T> void print(ArrayList<T> list) {

        for (T t : list) {
            System.out.println(t);
        }
    }

这个写法很简单,上文都讲过了,那么让我们来试着用一下吧:


public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        Test.print(list);
    }

打印的结果如下:

在这里插入图片描述

除了以上这种写法,我们还可以将其改成通配符的写法,先给大家上代码:


//?代表通配符  擦除机制  Object
    public static void print2(ArrayList<?> list) {
        for (Object t : list) {
            System.out.println(t);
        }
    }
}

此处for (Object t : list)必须这样写,因为通配符也是有擦除机制的,会在编译器编程Object类型。

2. 上界

语法:<? extends 上界>

示例:


public static void printAll(MyArrayList<? extends Number> list) {
...
    } 

代表可以传入类型实参是 Number 子类的任意类型的 MyArrayList
所以以下调用都是正确的:


printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Double>());
printAll(new MyArrayList<Number>());

以下调用都是错误的:


printAll(new MyArrayList<String>());
printAll(new MyArrayList<Object>());

3. 下界

下界和上界的用法很类似

语法:<? super 下界>

示例:


public static void printAll(MyArrayList<? super Integer> list) {
...
}

代表可以传入类型实参是 Integer 父类的任意类型的 MyArrayList
所以以下调用是正确的:


printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Number>());
printAll(new MyArrayList<Object>());

以下调用是错误的:


printAll(new MyArrayList<String>());
printAll(new MyArrayList<Double>());

六. 泛型的限制

学习完后,我们应该注意泛型使用过程中以下一些限制:

泛型类型参数不支持基本数据类型

无法实例化泛型类型的对象

无法使用泛型类型声明静态的属性

无法使用 instanceof 判断带类型参数的泛型类型(因为被擦除机制擦除了)

无法创建泛型类数组

无法 create、catch、throw 一个泛型类异常(异常不支持泛型)

泛型类型不是形参一部分,无法重载

在这里插入图片描述

好啦,本次泛型知识点的分享就先告一段落了,整理不易,但如果能帮到大家很开心了。也希望大家多理解理解,不论是刚开始学习还是复习,都值得仔细揣摩哦!一起加油吧!

到此这篇关于Java中的纸老虎之泛型的文章就介绍到这了,更多相关Java 泛型内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java中的纸老虎之泛型

本文链接: https://www.lsjlt.com/news/136236.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java中的纸老虎之泛型
    目录一. 泛型的定义二. 为什么要用到泛型三. 泛型的写法四. 泛型的使用实例1. 求最大值2. 优化五. 通配符1. 基本写法2. 上界3. 下界六. 泛型的限制泛型,其实算是Ja...
    99+
    2024-04-02
  • Java中的泛型
    目录1. 什么是泛型2. 为什么需要泛型3. 如何使用泛型3.1 泛型使用3.2 自定义泛型类3.2.1 Java 源码中泛型的定义3.2.2 自定义泛型类实例13.2.3 自定义泛...
    99+
    2024-04-02
  • Java中泛型学习之细节篇
    目录简介正文什么是类型参数为啥要有泛型泛型的演变史类型擦除泛型的应用场景通配符限定动态类型安全检查总结简介 泛型的作用就是把类型参数化,也就是我们常说的类型参数 平时我们接触的普通方...
    99+
    2024-04-02
  • 详解Java中的泛型
    目录一.什么是泛型二.泛型类的使用2.1泛型类的定义2.2泛型类的数组使用三.泛型的上界四.泛型的方法五.泛型与集合一.什么是泛型 当我们不确定数据类型时,我们可以暂时使用一个字母 ...
    99+
    2023-05-19
    Java泛型 Java泛型类
  • Java泛型之类型擦除实例详解
    目录前言泛型是什么?泛型的定义和使用泛型类泛型方法泛型类与泛型方法的共存现象泛型接口通配符?无限定通配符<><extendsT>类型擦除类型擦除带来的局限性泛...
    99+
    2024-04-02
  • Java基础之java泛型通配符详解
    前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型。 泛型的本质是参数化类型,也...
    99+
    2024-04-02
  • Java中的泛型怎么应用
    本篇内容介绍了“Java中的泛型怎么应用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!泛型概述泛型在java中有很重要的地位,在面向对象编程...
    99+
    2023-06-02
  • java中什么是泛型
    本篇文章给大家分享的是有关java中什么是泛型,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程...
    99+
    2023-06-14
  • Java中的泛型怎么理解
    本篇内容介绍了“Java中的泛型怎么理解”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!泛型:是JDK5中引入的特性,可以在编译阶段约束操作的...
    99+
    2023-06-30
  • 详解Java和Kotlin中的泛型
    详解Java和Kotlin中的泛型?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、泛型类型泛型允许你定义带类型形参的数据类型,当这种类型的实例被创建出来后,类型形参便被替换为...
    99+
    2023-06-15
  • Java中泛型的示例分析
    小编给大家分享一下Java中泛型的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1. 为什么使用泛型早期的Object类型可以接收任意的对象类型,但是在实...
    99+
    2023-06-20
  • Java中泛型的示例详解
    目录泛型概述使用泛型的好处泛型的定义与使用定义和使用含有泛型的类含有泛型的方法含有泛型的接口泛型通配符通配符基本使用通配符高级使用----受限泛型泛型概述 我们都知道集合中是可以存放...
    99+
    2022-11-13
    Java泛型机制 Java泛型
  • Java泛型的解析
    这期内容当中小编将会给大家带来有关Java泛型的解析,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一、泛型简介1.1 泛型的概念 所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是...
    99+
    2023-06-15
  • java中的泛型指的是什么
    这篇文章主要讲解了“java中的泛型指的是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java中的泛型指的是什么”吧!目录一、什么是泛型二、语法三、示例简单示例返回最大值-支持各种数据...
    99+
    2023-06-20
  • Java 泛型详解(超详细的java泛型方法解析)
    目录2. 什么是泛型3. 使用泛型的好处4. 泛型的使用4.1 泛型类4.2 泛型方法4.3 泛型接口5. 泛型通配符5.1 通配符基本使用5.2 通配符高级使用6. 总结1. 为什...
    99+
    2024-04-02
  • java基础之泛型知识点总结
    目录一、什么是泛型?为什么要使用泛型? 二、泛型的特性是什么?三、泛型的使用方式 四、Java中的泛型通配符一、什么是泛型?为什么要使用泛型? 泛型,即“参数化...
    99+
    2024-04-02
  • Java中怎么擦除泛型类型
    Java中怎么擦除泛型类型,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。前言Java泛型这个特性是从JDK 1.5才开始加入的,因此为了兼容之前的版本,Java泛型的实现采...
    99+
    2023-06-20
  • Java中泛型有什么用
    这篇文章主要介绍了Java中泛型有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。泛型1、简单泛型泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保...
    99+
    2023-06-20
  • Java中的泛型是什么意思
    这篇文章主要介绍“Java中的泛型是什么意思”,在日常操作中,相信很多人在Java中的泛型是什么意思问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的泛型是什么意思”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-03
  • Java知识梳理之泛型用法详解
    目录泛型作用集合中泛型自定义泛型通配符2.注意点3.有限制的通配符泛型 背景: 从JDK 5.0以后,Java引入了“参数化类型(Parameterized type)&...
    99+
    2022-11-13
    Java泛型用法 Java泛型
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作