Java:泛型小记
Java:泛型小记
对 Java 中的 泛型类,做一个微不足道的小小小小记
泛型实现
概述
开篇:
List<String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass()); // 存在类型擦除:true
泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。
例如:List<String>
在运行时仅用一个 List 来表示。这样做的目的,是确保能和 Java 5 之前的版本开发二进制类库进行兼容。
类型擦除:
泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。
在泛型类被类型擦除的时候,之前泛型类中的类型参数部分如果没有指定上限,如 <T>
则会被转译成普通的 Object 类型,如果指定了上限如 <T extends String>
则类型参数就被替换成类型上限。
泛型中值得注意的地方:
泛型类或者泛型方法中,不接受 8 种基本数据类型
// 无法通过编译
List<int> li1 = new ArrayList<>();
List<boolean> li2 = new ArrayList<>();
// 需要转换成其包装类
List<Integer> li1 = new ArrayList<>();
List<Boolean> li2 = new ArrayList<>();
Java 不能创建具体类型的泛型数组
// 无法通过编译
List<Integer>[] li3 = new ArrayList<Integer>[];
List<Boolean>[] li4 = new ArrayList<Boolean>[];
原因还是类型擦除带来的影响,
List<Integer>
和List<Boolean>
在 JVM 中等同于List<Object>
, 所有的类型信息都被擦除, 程序也无法分辨一个数组中的元素类型具体是List<Integer>
类型还是List<Boolean>
类型。
补充:
List<String> list = new ArrayList<String>();
1、两个 String 其实只有第一个起作用,后面一个没什么卵用,只不过 JDK7 才开始支持
List<String>list = new ArrayList<>
这种写法。2、第一个 String 就是告诉编译器,List 中存储的是 String 对象,也就是起类型检查的作用,之后编译器会擦除泛型占位符,以保证兼容以前的代码。
通配符
通配符 ?
:除了用 <T>
表示泛型外,还有 <?>
这种形式。?
被称为通配符。
为何需要引入通配符
?
的概念:class Base{}
class Sub extends Base{} // 以下代码无问题:
Sub sub = new Sub();
Base base = sub;
List<Sub> lsub = new ArrayList<>();
// error! 无法编译通过
List<Base> lbase = lsub;
编译器不会让它通过的。Sub 是 Base 的子类,不代表
List<Sub>
和List<Base>
有继承关系。但是,在现实编码中,确实有这样的需求,希望泛型能够处理某一范围内的数据类型,比如某个类和它的子类,对此 Java 引入了通配符这个概念。
因此,通配符的出现是为了指定泛型中的类型范围。
通配符的三种形式:
<?>
被称作无限定的通配符。<? extends T>
被称作有上限的通配符。<? super T>
被称作有下限的通配符。
无限定的通配符?
:它其中的 ?
其实代表的是未知类型,所以涉及到 ?
时的操作,一定与具体类型无关;
有上限的通配符<? extends T>
:
确保类型必须是 T 的子类来设定类型的上界,例如 List<? extends Number>
可以接受 List<Integer>
或 List<Float>
。
有下限的通配符<? super T>
它通过确保类型必须是 T 的父类来设定类型的下界
// 定义类
class Person{
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student() {
}
public Student(String name) {
super(name);
}
}
class Animal{
private String name;
public Animal(String name) {
this.name = name;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
'}';
}
}
@Test
public void test06(){
ArrayList<Person> persons = new ArrayList<>();
persons.add(new Person("张三"));
persons.add(new Person("李四"));
persons.add(new Person("王五"));
printOnlyPerson(persons);
printPerson(persons);
printWho(persons);
ArrayList<Student> students = new ArrayList<Student>();
students.add(new Student("小红"));
students.add(new Student("小明"));
students.add(new Student("小丁"));
// printOnlyPerson(students); // error
printPerson(persons);
printWho(persons);
ArrayList<Animal> animal = new ArrayList<Animal>();
animal.add(new Animal("小猫"));
animal.add(new Animal("小狗"));
animal.add(new Animal("小鸟"));
// printOnlyPerson(animal); // error
// printPerson(animal); // error
printWho(animal);
}
// 只能打印限定Person类别
public void printOnlyPerson(ArrayList<Person> persons){
Iterator<Person> iterator = persons.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().toString());
}
}
// 可以打印Person类及其子类
public void printPerson(ArrayList<? extends Person> persons){
Iterator<? extends Person> iterator = persons.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().toString());
}
}
// 可以打印任何东西
public void printWho(ArrayList<?> who){
Iterator<?> iterator = who.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next().toString());
}
}
补充:Array 不支持泛型,要用 List 代替 Array,因为 List 可以提供编译器的类型安全保证,而 Array 却不能。
参考
https://blog.csdn.net/briblue/article/details/76736356
Java:泛型小记的更多相关文章
- Java泛型小记
Automobile类: public class Automobile { private String name; public Automobile(String name){ this.nam ...
- Java泛型的历史
为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...
- 浅析Java 泛型
泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...
- Java:泛型基础
泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...
- java泛型基础
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法. Ja ...
- 使用java泛型设计通用方法
泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...
- 关于Java泛型的使用
在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Wind ...
- 初识java泛型
1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...
- 【Java心得总结四】Java泛型下——万恶的擦除
一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...
随机推荐
- python基础--网站推荐
Python教程 - 廖雪峰的官方网站 Python 基础教程 | 菜鸟教程 随笔分类 - 机器学习
- 现在互联网好多bug 想到都烦
我接触计算机十多年了,只是在15年前发布一篇给计算机有关的技术文章,后来就在也不发表了,今天在163博客写个备录,,写到一半结果误 关了,,浪费了好几个小时,还以为像以前那样,又要重写,,这也是我不爱 ...
- CodeForce-782B The Meeting Place Cannot Be Changed(高精度二分)
https://vjudge.net/problem/CodeForces-782B B. The Meeting Place Cannot Be Changed time limit per tes ...
- nginx proxy_next_upstream 与openresty balancer.set_more_tries的使用
背景 我们这边网关服务使用的 kong,前段时间上线一个服务,这个服务它报错了,产生了502的错误码,追查这个报错的时候发现了网关服务的两个可疑的地方,第一个疑点是我们在Kong上配置的 Retrie ...
- js 之k个一组翻转链表
题目描述 将给出的链表中的节点每\ k k 个一组翻转,返回翻转后的链表如果链表中的节点数不是\ k k 的倍数,将最后剩下的节点保持原样你不能更改节点中的值,只能更改节点本身.要求空间复杂度 \ O ...
- Nacos注册中心和配置中心流程原理
一.Nacos注册中心 1.服务启动后---->服务注册原理 springCloud集成Nacos实现原理: 服务启动时,在spring-cloud-commons包下 spring.facto ...
- FormData上传文件 带进度条
* jQuery ajax FormData 上传文件 template $.ajax({ url: url, type: 'POST', data: new FormData(form), dat ...
- 浅聊Linux的五种IO模型
在日常 Coding 中,多多少少都会接触到网络 IO,就会想要深入了解一下.看了很多文章,总是云里雾里的感觉,直到读了<UNIX网络编程 卷1:套接字联网API>中的介绍后,才豁然开朗. ...
- P6640-[BJOI2020]封印【SAM,二分】
正题 题目链接:https://www.luogu.com.cn/problem/P6640 题目大意 给出两个字符串\(s,t\).\(q\)次给出\(l,r\)询问\(s_{l\sim r}\)与 ...
- P4707-重返现世【dp,数学期望,扩展min-max容斥】
正题 题目链接:https://www.luogu.com.cn/problem/P4707 题目大意 \(n\)个物品,每次生成一种物品,第\(i\)个被生成的概率是\(\frac{p_i}{m}\ ...