当前位置: 首页 > news >正文

35.Java 中的泛型是什么

35.Java 中的泛型是什么

泛型就是将类型参数化,在编译时再确定类型。可以实现在类,接口,方法中。

  • 泛型类

    • public class Box<T> {private T value;public void set(T value) {this.value = value;}public T get() {return value;}
      }
      
    • Box<String> stringBox = new Box<>();
      stringBox.set("Hello");
      String str = stringBox.get(); // 直接获取String类型,无需强制转换Box<Integer> intBox = new Box<>();
      intBox.set(123);
      int num = intBox.get(); // 直接获取Integer类型
      
  • 泛型接口

    • public interface Repository<T, ID> {T findById(ID id);void save(T entity);
      }
      
    • public class UserRepository implements Repository<User, Long> {@Overridepublic User findById(Long id) {// 根据ID查找User}@Overridepublic void save(User user) {// 保存User}
      }
      
  • 泛型方法

    • public class ArrayUtils {public static <T> void printArray(T[] array) {for (T element : array) {System.out.println(element);}}
      }
      
    • String[] names = {"Tom", "Jerry"};
      ArrayUtils.printArray(names); // 处理String数组Integer[] numbers = {1, 2, 3};
      ArrayUtils.printArray(numbers); // 处理Integer数组
      

使用泛型的好处是什么

在java1.4版本,是没有泛型概念的;只能用Object来实现。Object有两个缺点

  1. 每次使用的时候必须要进行强制转换
  2. 在编译时编译器不知道类型转换是否正常,在运行时就会报出异常

sun公司为了Java更加安全,引入了泛型

  1. 类型安全
    • 在编译的时候就可以检查出类型转换的异常
  2. 消除强制类型转换
    • 使用的时候可以直接得到想要的数据类型
  3. 提升性能
    • 在编译时直接完成

泛型是一种语法糖,基本原理就是进行类型擦除;在编译之后,就会擦去类型参数。

public class Caculate<T> {private T num;
}

我们定义了一个泛型类,定义了一个属性成员,该成员的类型是一个泛型类型,这个 T 具体是什么类型,我们也不知道,它只是用于限定类型的。反编译一下这个 Caculate 类:

public class Caculate{public Caculate(){}private Object num;
}

发现编译器擦除 Caculate 类后面的两个尖括号,并且将 num 的类型定义为 Object 类型。

那么是不是所有的泛型类型都以 Object 进行擦除呢?大部分情况下,泛型类型都会以 Object 进行替换,而有一种情况则不是。那就是使用到了extends和super语法的有界类型,如:

public class Caculate<T extends String> {private T num;
}

这种情况的泛型类型,num 会被替换为 String 而不再是 Object。这是一个类型限定的语法,它限定 T 是 String 或者 String 的子类,也就是你构建 Caculate 实例的时候只能限定 T 为 String 或者 String的子类,所以无论你限定 T 为什么类型,String 都是父类,不会出现类型不匹配的问题,于是可以使用String 进行类型擦除。

实际上编译器会正常的将使用泛型的地方编译并进行类型擦除,然后返回实例。但是除此之外的是,如果构建泛型实例时使用了泛型语法,那么编译器将标记该实例并关注该实例后续所有方法的调用,每次调用前都进行安全检查,非指定类型的方法都不能调用成功。

实际上编译器不仅关注一个泛型方法的调用,它还会为某些返回值为限定的泛型类型的方法进行强制类型转换,由于类型擦除,返回值为泛型类型的方法都会擦除成 Object 类型,当这些方法被调用后,编译器会额外插入一行 checkcast 指令用于强制类型转换。这一个过程就叫做『泛型翻译』。

什么是泛型中的限定通配符和非限定通配符

  • 限定通配符
    • <? extends T> 可以是T或者是T的子类;上界通配符
    • <? super T> 可以是T或者是T的父类;下界通配符
  • 非限定通配符
    • <?> 可以匹配任意类型,

List<? extends T>和List <? super T>之间有什么区别?

  • List<? extends T> 上界通配符,只可以读取,不能写入。

  • List<? extends Number> list = new ArrayList<Integer>();
    Number number = list.get(0); // ✅ 可读
    list.add(10);                // ❌ 编译报错:无法添加
    
  • List <? super T> 下界通配符,只可以写入,不能读取

    • List<? super Integer> list = new ArrayList<Number>();
      list.add(10);        // ✅ 可写入 Integer
      Number num = (Number) list.get(0); // ✅ 可读,但需要强制转换
      

判断ArrayList与ArrayList是否相等?

ArrayList<String> a = new ArrayList<String>();
ArrayList<Integer> b = new ArrayList<Integer>();
Class c1 = a.getClass();
Class c2 = b.getClass();
System.out.println(c1 == c2);

输出的结果是 true。因为无论对于 ArrayList 还是 ArrayList,它们的 Class 类型都是一直的,都是ArrayList.class。

原因

  • Java 的泛型在运行时会进行 类型擦除(Type Erasure)。无论泛型参数是什么,最终的类对象都是 ArrayList.class
  • 因此,ArrayList<String>ArrayList<Integer> 在运行时都被视为 ArrayList,它们的类对象是相同的。

那它们声明时指定的 String 和 Integer 到底体现在哪里呢?答案是体现在类编译的时候。当 JVM 进行类编译时,会进行泛型检查,如果一个集合被声明为 String类型,那么它往该集合存取数据的时候就会对数据进行判断,从而避免存入或取出错误的数据。

Array中可以用泛型吗?

不可以,因为 List可以提供编译期的类型安全保证,而 Array 却不能。


文章转载自:

http://mkfNgFqh.Ljygq.cn
http://2D4XnAKv.Ljygq.cn
http://udwf56Kw.Ljygq.cn
http://wOMJcRhj.Ljygq.cn
http://pkGJxM0W.Ljygq.cn
http://lQdX3d18.Ljygq.cn
http://EjWsWJQy.Ljygq.cn
http://owrnp3Sk.Ljygq.cn
http://hl4vMGgH.Ljygq.cn
http://oYlayPzT.Ljygq.cn
http://7aO4Lnap.Ljygq.cn
http://RHNoTkLM.Ljygq.cn
http://E7ba2opi.Ljygq.cn
http://wRE94ThX.Ljygq.cn
http://zhaHtryn.Ljygq.cn
http://ZjG9ZLJu.Ljygq.cn
http://clXREbGE.Ljygq.cn
http://olxoZYrn.Ljygq.cn
http://h6LgoqID.Ljygq.cn
http://qYHjx8Um.Ljygq.cn
http://kJ4xq3gY.Ljygq.cn
http://OXNVzZf0.Ljygq.cn
http://bbamA36D.Ljygq.cn
http://WIBBj3Yb.Ljygq.cn
http://c5BjOqSb.Ljygq.cn
http://VmNHR4Jb.Ljygq.cn
http://zA5KZdI1.Ljygq.cn
http://b0ObGev5.Ljygq.cn
http://A85tpIJr.Ljygq.cn
http://1AO37zM3.Ljygq.cn
http://www.dtcms.com/a/372970.html

相关文章:

  • commons-compress
  • Acwing算法基础课--高精度加减乘除
  • 【前端】Promise对象的实现-JavaScript
  • 第5篇 pytorch卸载方法与更换版本
  • 56.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--新增功能--实现手机邮箱找回密码
  • 月2期学习笔记
  • [新启航]新启航激光频率梳方案:击穿光学遮挡壁垒,以 2μm 精度实现 130mm 深孔 3D 轮廓测量
  • 51单片机驱动数码管
  • 51单片机基础结构及编程要点
  • Git Bash 别名
  • 福彩双色球第2025104期篮球号码分析
  • C++模板进阶:从基础到高级实战技巧
  • 力扣每日一题p1317 将整数转换…… 题解
  • 量子密码:后量子的加密
  • 【 ​​SQL注入漏洞靶场】第二关文件读写
  • wpf .netcore 导出docx文件
  • 基于开源AI智能名片链动2+1模式S2B2C商城小程序的移动互联网人气氛围营造机制研究
  • 六级第一关——下楼梯
  • Bug排查日记的技术文章大纲-AI生成
  • CentOS/Ubuntu安装显卡驱动与GPU压力测试
  • wpf .netcore 导出pdf文件
  • 6个步骤实现Postman接口压力测试
  • Linux-expect脚本编程
  • Dart 聊天后端开发(MongoDB + WebSocket)
  • Linux初始——自动化构建
  • Linux之GDB调试
  • 通俗理解 LSTM 的三门机制:从剧情记忆到科学原理
  • MyBatis-Plus中 IService 与 ServiceImpl等内容的深入思考理解
  • Android使用ReactiveNetwork监听网络连通性
  • 大学信息查询平台:一个现代化的React教育项目