码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 一文搞懂泛型——泛型简介/优点/上界/通配符


    目录

    1.泛型简介

    2.泛型的优点

    3.泛型的上界

    2.1 特殊的泛型上界

    4.泛型的通配符

    4.1 简介

    4.2 通配符的上界

    4.3 通配符的下界


    1.泛型简介

             一般的类或者方法,只能运用具体的类型:即基本类型、自定义的类。若要编写可以用于多种类型的代码,这种刻板的限制对编写代码的束缚会很大。                                   ——《Java编程思想》

            泛型是JDK5.1引入的语法,通俗的讲,泛型就是适用于许多的类型,代码上讲是对类型实现了参数化。

            泛型是Java中比较难的语法

    例如:

    1. class MyArray{
    2. public Object[] objects = new Object[10];
    3. public void set(int pos,Object val){
    4. objects[pos] = val;
    5. }
    6. public Object get(int pos){
    7. return objects[pos];
    8. }
    9. }
    10. public class Main {
    11. public static void main(String[] args) {
    12. MyArray myArray = new MyArray();
    13. myArray.set(0,"hello");
    14. String str = myArray.get(0);
    15. String str1 = myArray.get(0);
    16. System.out.println(str1);
    17. }
    18. }

            对于以上代码,虽然指定了MyArray类中的objects数组类型为Object,并且在main函数中,让objects数组的0下标为字符串“hello”,但在“String str = myArray.get(0);”这行代码中会报错,只能进行强制类型转换,才可输出“hello”。

            对于以上问题,就可以利用泛型。将类名改为“MyArray”,此时,MyArray就是一个泛型类“T”可当作是一个占位符。同时更改类中的类型名称。

    上述代数可更改为:

    1. class MyArray{
    2. public T[] objects = (T[])new Object[10];
    3. public void set(int pos,T val){
    4. objects[pos] = val;
    5. }
    6. public T get(int pos){
    7. return objects[pos];
    8. }
    9. }
    10. public class Main{
    11. public static void main(String[] args) {
    12. MyArray myArray = new MyArray();
    13. myArray.set(0,"hello");
    14. myArray.set(1,10);
    15. String str = myArray.get(0);
    16. System.out.println(str);
    17. }
    18. }

            在My Array类中,将Object类型改为T类型,在main函数中,MyArray后加上想要的类型,此时加的是,这样“String str = myArray.get(0);”就不报错了,不用再进行强制类型转换。但是“myArray.set(1,10);”这行代码会报错。即就是编译的时候,会自动进行类型检查。

            再看如下代码

    1. public class Main{
    2. public static void main(String[] args) {
    3. MyArray myArray = new MyArray();
    4. myArray.set(0,"hello");
    5. myArray.set(1,10);
    6. String str = myArray.get(0);
    7. System.out.println(str);
    8. MyArray myArray2 = new MyArray();
    9. MyArray<int> myArray3 = new MyArray<int>();
    10. }
    11. }

            “MyArray myArray2 = new MyArray();”不报错
            “MyArray myArray3 = new MyArray();”报错

            这表明对于基本类型来说,不能作为泛型类型的参数。

    原类型包装类
    byteByte
    shortShort
    intInteger
    longLong
    floatFloat
    doubleDouble
    charCharacter
    booleanBoolean

    2.泛型的优点

    1.数据类型参数化

    2.编译时会自动进行类型的检查与转换

    接下类从底层看一下泛型

    在Java当前的文档中打开至这个界面,可根据

     此处在空白处鼠标单击右键,选择用powershell打开,并输入指令“javap -c MyArray”,回车

    发现有好多的Objec。这表名编译当中,所有的T替换为Obejct,这种替换方式称为:擦除机制

    详细的泛型及泛型的擦除机制介绍:https://zhuanlan.zhihu.com/p/51452375

    3.泛型的上界

    例如

    public class MyArray{

            ......

    }

    此时 “MyArray myArray = new MyArray();”

            “MyArray myArray = new MyArray();”都是可以的,但是

            “MyArray myArray = new MyArray();”会报错。因为E只能是Nubmer或者Number的子类。这就是泛型的上界。泛型没有下界

    public class MyArray{

            ......

    }

    没有指定上界,则默认是Object,视为

    2.1 特殊的泛型上界

    这是一个寻找数组最大值的方法,类中是T类型的参数        

    1. class Find{
    2. public T findMax(T[] array){
    3. T max = array[0];
    4. for (int i = 1; i < array.length; i++) {
    5. if(max < array[i]){
    6. max = array[i];
    7. }
    8. }
    9. return max;
    10. }
    11. }

            此时发现“ if(max < array[i])”这行代码报错了。原因是T类型是引用类型,无法通过“< ,> ,!=”等比较,需要利用compare进行比较。

            则以上代码更改为

    1. class Findextends Comparable>{
    2. public T findMax(T[] array){
    3. T max = array[0];
    4. for (int i = 1; i < array.length; i++) {
    5. if(max.compareTo(array[i]) < 0 ){
    6. max = array[i];
    7. }
    8. }
    9. return max;
    10. }
    11. }

    测试用例:

    1. public class Main {
    2. public static void main(String[] args) {
    3. Integer[] array = {2,34,45,12,76,80,22,35,10};
    4. Find find = new Find();
    5. int max = find.findMax(array);
    6. System.out.println("array数组最大值为: " + max);
    7. String[] strings = {"hello","i love u","qwerty"};
    8. Find find2 = new Find();
    9. String str = find2.findMax(strings);
    10. System.out.println("str数组最大值为: " + str);
    11. }
    12. }

    测试结果:

     注意:这里的extends不是继承

    4.泛型的通配符

    4.1 简介

            通配符是为了解决泛型无法协变的问题,协变是指如果Student是Person的子类,那么List也应该是List的子类。但是泛型是不支持这样的父子类关系。

            1.泛型T是一个确定的类型,一旦传入类型就确定下来,而通配符更加灵活且不确定,更多的是用于扩充参数的范围。

            2.可以理解为T就是一个变量,传入具体的类型就确定下来,而通配符可以规定能传那些参数。

    例如

    1. class Alg{
    2. public static void print1(ArrayList list){
    3. for (T x:list) {
    4. System.out.println(x);
    5. }
    6. }
    7. public static void print2(ArrayList list){
    8. for (Object x:list) {
    9. System.out.println(list);
    10. }
    11. }
    12. }

    4.2 通配符的上界

    语法:
    举例:
    1. // 可以传入类型实参是 Number 子类的任意类型的 MyArrayList
    2. public static void printAll(MyArrayList list) {
    3. ...
    4. }
    5. // 以下调用都是正确的
    6. printAll(new MyArrayList());
    7. printAll(new MyArrayList());
    8. printAll(new MyArrayList());
    9. // 以下调用是编译错误的
    10. printAll(new MyArrayList());
    11. printAll(new MyArrayList());

      4.3 通配符的下界

      语法:

      举例:

      1. // 可以传入类型实参是 Integer 父类的任意类型的 MyArrayList
      2. public static void printAll(MyArrayListsuper Integer> list) {
      3. ...
      4. }
      5. // 以下调用都是正确的
      6. printAll(new MyArrayList());
      7. printAll(new MyArrayList());
      8. printAll(new MyArrayList());
      9. // 以下调用是编译错误的
      10. printAll(new MyArrayList());
      11. printAll(new MyArrayList());
      12. 相关阅读:
        2023年浙大MEM英语二作文干货模版:临阵磨枪可用
        JAVA多线程进阶篇-探索线程池ThreadPoolExecutor源码
        UML类图以及常用集合
        是时候,重新认识一下项目经理了
        白蛋白纳米粒|莫西沙星小鼠血清白蛋白MSA纳米粒|利多卡因大鼠血清白蛋白RSA纳米粒
        QT:QSS自定义 QCheckBox实例
        包含文心一言在内的首批国产大模型 全面开放
        uni-app总结
        《时代》专访ChatGPT之父:人工智能影响经济还需要很多年
        什么!程序员不乖乖写代码,跑去写小说了?一时兴起写了《雪中悍刀行》的番外,请品鉴!
      13. 原文地址:https://blog.csdn.net/m0_57950108/article/details/127708929
        • 最新文章
        • 攻防演习之三天拿下官网站群
          数据安全治理学习——前期安全规划和安全管理体系建设
          企业安全 | 企业内一次钓鱼演练准备过程
          内网渗透测试 | Kerberos协议及其部分攻击手法
          0day的产生 | 不懂代码的"代码审计"
          安装scrcpy-client模块av模块异常,环境问题解决方案
          leetcode hot100【LeetCode 279. 完全平方数】java实现
          OpenWrt下安装Mosquitto
          AnatoMask论文汇总
          【AI日记】24.11.01 LangChain、openai api和github copilot
        • 热门文章
        • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
          奉劝各位学弟学妹们,该打造你的技术影响力了!
          五年了,我在 CSDN 的两个一百万。
          Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
          面试官都震惊,你这网络基础可以啊!
          你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
          心情不好的时候,用 Python 画棵樱花树送给自己吧
          通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
          13 万字 C 语言从入门到精通保姆级教程2021 年版
          10行代码集2000张美女图,Python爬虫120例,再上征途
        Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
        正则表达式工具 cron表达式工具 密码生成工具

        京公网安备 11010502049817号