Java的泛型机制

泛型是 Java 从 JDK5 开始引入的新特性,本质上是参数化类型,即所操作的数据类型被指定为一个参数。这意味着编写的代码可以被很多不同类型的对象所重用。

1. 泛型的使用方式

1.1 泛型类

用下面的语法可以定义一个泛型类:

class C< T, E, ...>{
private T t;
...
}

常用的泛型标识有 T、E、K、V。

用下面的语法可以创建一个泛型对象:

C<具体的数据类型> c = new C<>();

泛型类有以下注意事项:

  • 如果没有指定具体的数据类型,操作类型是 Object。
  • 泛型的类型参数只能是类类型,不能是基本数据类型。
  • 泛型类型在逻辑上看作多个不同类型,但实际上是相同类型。

用下面的语法可以从泛型类派生子类:

// 子类也是泛型类,要和父类的泛型类型保持一致。但可以添加更多类型。
class Child<T> extends Father<T>
class Child<T, E, K> extends Father<T>
// 子类不是泛型类,父类要明确一个泛型的数据类型
class Child extends Father<String>

1.2 泛型接口

定义方式类似于泛型类。

当需要用一个类实现泛型接口时:

  • 如果实现类不是泛型类,接口要明确数据类型。
  • 如果实现类是泛型类,实现类和接口的泛型类型要一致,但也可以增加更多。

1.3 泛型方法

用下面的语法可以定义一个泛型方法:

public <T, E, ...> void f(){
...
}

泛型类的类型由构造对象时决定,泛型方法的类型由调用方法时决定。

1.4 类型通配符

我们用?作为类型通配符,代表具体的类型实参。

使用extends语句可以代表类型通配符的上限:

类/接口<? extends 实参类型>

要求该泛型的类型,只能是实参类型或者实参类型的子类类型。

使用super语句可以代表类型通配符的下限:

类/接口<? super 实参类型>

带有超类型限定的通配符可以向泛型对象写入,带有子类型限定的通配符可以从泛型对象读取。

2. 类型擦除式泛型

Java 的泛型实现方式是类型擦除的伪泛型。在 Java 中,泛型只在程序源码中存在,编译后的字节码文件中泛型全部被擦除,替换为原来的裸类型,并在相应的位置插入了强制转型代码。

假设我们有下面这段代码:

public static void main(String[] args){
Map<String, String> map = new HashMap<String, String>();
map.put("hello", "你好");
System.out.pirntln(map.get("hello"));
}

这里向泛型类型为<Stirng, String>的 map 内插入了一个键值对,又从中将值取出。如果我们先将这段 Java 代码编译为 Class 文件,又反编译 Class 文件,实际上会得到以下代码:

public static void main(String[] args){
Map map = new HashMap();
map.put("hello", "你好");
System.out.pirntln((String)map.get("hello"));
}

显然,在前端编译过程中,对象的泛型类型被擦除,转换为了没有泛型的裸类型。而在字节码文件的相关位置插入了强制类型转换代码,从而实现泛型。

类型擦除式的泛型带来了几个严重的问题:

Ⅰ. 不支持基础数据类型的泛型

由于我们无法在 int、long 等基础数据类型和 Object 之间强制转型,所以 Java 的泛型不支持基础数据类型。

Ⅱ. 运行时无法获取泛型类型信息

加入我们想写一个泛型版本的 List 转换为数组的方法,由于不能再运行时获取泛型信息,只能再传入一个元素的类型。

public static <T> T[] convert(List<T> list, Class<T> componentType){
Tp[] array = (T[])Array.newInstance(componentType, list.size());
}

Ⅲ. 无法正常的实现重载等功能

例如两个方法我们试图依赖泛型类型不同来实现重载,就会发生编译错误。因为泛型类型在前端编译器被擦除了,变成了两个一模一样的方法。

3. 桥接方法的机制

当一个类实现一个泛型接口时,泛型接口在编译后类型被擦除,这样我们在实现类中就不能找到对应接口的实现方法。为了解决这个问题,Java 在编译相关类时使用了一个桥接方法的机制,通过为实现类新增一个桥接方法,来实现类型擦除后接口的方法。

Java的泛型机制的更多相关文章

  1. Java进阶 | 泛型机制与反射原理

    一.泛型的概念 1.基础案例 泛型在Java中的应用非常广泛,最常见则是在集合容器中,先看下基础用法: public class Generic01 { public static void main ...

  2. java基础---泛型机制

    从java5 开始增加泛型机制,用于明确集合中可以放入的元素类型,只在编译时期有效,运行时不区分是什么类型. 格式:<数据类型> 泛型的本质是参数化类型,让数据类型作为参数传递,E相当于形 ...

  3. Java类型擦除机制

    Java泛型是JDK 5引入的一个特性,它允许我们定义类和接口的时候使用参数类型,泛型在集合框架中被广泛使用.类型擦除是泛型中最让人困惑的部分,本篇文章将阐明什么是类型擦除,以及如何使用它. 一个常见 ...

  4. 【Java】泛型学习笔记

    参考书籍 <Java核心技术:卷1> 泛型, 先睹为快 先通过一个简单的例子说明下Java中泛型的用法: 泛型的基本形式类似于模板, 通过一个类型参数T, 你可以"私人定制&qu ...

  5. Java 之泛型通配符 ? extends T 与 ? super T 解惑

    简述 大家在平时的工作学习中, 肯定会见过不少如下的语句: List<? super T> List<? extends T> 我们都知道, 上面的代码时关于 Java 泛型的 ...

  6. Java泛型机制

    泛型程序设计 1.泛型程序设计的起源? 泛型是JDK1.5增加的新特性. 2.使用泛型的好处? 使用泛型机制编写的代码比那些杂乱使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读 ...

  7. 深入理解Java之泛型

    原文出处: absfree 1. Why ——引入泛型机制的原因 假如我们想要实现一个String数组,并且要求它可以动态改变大小,这时我们都会想到用ArrayList来聚合String对象.然而,过 ...

  8. Java的多线程机制系列:(一)总述及基础概念

    前言 这一系列多线程的文章,一方面是个人对Java现有的多线程机制的学习和记录,另一方面是希望能给不熟悉Java多线程机制.或有一定基础但理解还不够深的读者一个比较全面的介绍,旨在使读者对Java的多 ...

  9. Java 类反射机制分析

    Java 类反射机制分析 一.反射的概念及在Java中的类反射 反射主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.在计算机科学领域,反射是一类应用,它们能够自描述和自控制.这类应用通过某 ...

随机推荐

  1. SYCOJ411

    题面描述 MasMas在面试某大厂时遇到了一道有趣的题.面试官要求MasMas写一个程序找出几个数中,出现次数为奇数的那个数.MasMas抓耳挠腮,请你帮帮他. 输入描述 第一行输入一个数nn (1 ...

  2. SpringBoot2.4.2下配置Lettuce使用Redis

    1. Springboot2.4.2下对Redis的基础集成 1.1 maven添加依赖 <dependency> <groupId>org.springframework.b ...

  3. JUC并发编程与高性能内存队列disruptor实战-上

    JUC并发实战 Synchonized与Lock 区别 Synchronized是Java的关键字,由JVM层面实现的,Lock是一个接口,有实现类,由JDK实现. Synchronized无法获取锁 ...

  4. 以太 ip tcp udp 三次握手的理解

    以太帧: 1.前导码(7字节):使接收器建立比特同步. 2.起始定界符SFD(1字节):指示一帧的开始. 3.目的地址DA(6字节):指出要接收该帧的工作站. 4.源地址SA(6字节):指示发送该帧的 ...

  5. 利用栈实现括号匹配(python语言)

    原理: 右括号总是与最近的左括号匹配 --- 栈的后进先出 从左往右遍历字符串,遇到左括号就入栈,遇到右括号时,就出栈一个元素与其配对 当栈为空时,遇到右括号,则此右括号无与之匹配的左括号 当最终右括 ...

  6. 《剑指offer》面试题33. 二叉搜索树的后序遍历序列

    问题描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果.如果是则返回 true,否则返回 false.假设输入的数组的任意两个数字都互不相同.   参考以下这颗二叉搜索树: 5 / \ ...

  7. 【C++】STL算法

    STL算法 标签:c++ 目录 STL算法 一.不变序列算法 1.熟悉的min(), max() 2.找最值还自己动手么?不了不了 3.熟悉的find()和新学会的count() 二.变值算法 1.f ...

  8. 【小记录】android命令行程序发生coredump后读取堆栈信息

    一开始执行: adb shell cd /data/local/tmp ulimit -c unlimited ./xxx 然后查看coredump文件信息: adb pull /data/local ...

  9. 与Elasticsearch交互的客户端

    1.访问ES的方式 访问es的方式有两种,一种是http方式,还有一种是java客户端方式. 其中Java客户端又分为:1.1.Node client: 节点客户端实际上是一个集群中的节点(但不保存数 ...

  10. 数组的sort()排序

    1.sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点,也就是你不传参进去的话,默认按字符串Unicode码点来排序,而不是按数字大小来排序 2.arr ...