15个问题告诉你如何使用Java泛型
摘要:Java泛型其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
Java泛型是J2 SE1.5中引入的一个新特性,其本质是参数化类型,也就是说所操作的数据类型被指定为一个参数(type parameter)这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型方法
一般定义如下,即方法的前面加了个<T>
public class FTest {
public <T> List<T> f(T t){...};
}
三种泛型参数推断方式:
1、直接在f()前面加确定泛型
fTest.<Integer>f(xxx)
2、通过输入参数确定, 下面这个推断为Integer
int number = 0;
fTest.f(number)
3、可通过 返回值 确定
List<Integer> list = fTest.f(xxx);
Q: 下面这段代码哪里有问题? 是toString()那里吗?
public class A<T> {
public static void test(T t){
System.out.println(t.toString());
}
}
A:test是static方法, 因此无法感知A<T>实例里的T
需要改成
public static <T> void test(T t)
toString()那里没问题,toString就是Object的方法。
泛型参数和类型消除
Q: 泛型参数T在运行时,会变成什么?
A: 统一变成Object且不包含任何类型信息。
Q: 泛型参数T可以可以使用instanceof做比较吗?
class A<T> {
void f(Object arg)
if(arg instanceof T) {
...
}
}
A: 不能,编译器会报错。
Q: 泛型参数T可以进行new T()或者new T[]操作吗?
A: 不能,编译器会报错。

Q: 能调用泛型参数对象里的方法吗?
T.f();
A: 只能调用Object的方法。
Q: 可以用T做强制转化吗?
T t = (T)object;
A: 能运行, 但不会真正发生转型, 编译时会触发waring警告。
新建泛型对象时的问题
先假定有2个类, 基类Parent 和子类Child
class Parent{}
class Child extends Parent{}
回答以下问题:
Q:下面这句话有问题吗?
List<Parent> list = new ArrayList<Child>()
A:有问题,编译就错误了。 List<Parent>和ArrayList<Child>并不存在父子类的关系
Q:
List<? extends Parent> list = new ArrayList<Child>();
这个list有什么特点?
A:这个list可以调用A a = list.get(), 但是不能list.add(new Parent())
- 原因:
list.get()所做的操作是在返回时, 把内部的<? extend Parent> 强转成Parent, 是合理的,任何Parent的子类都可以转成Parent
list.add(new Parent())所做的操作是在输入时, 把外部的A转成内部的<? extend Parent>, 这是不合理的,因为我们不知道这个Parent对象可以转成哪个Parent的子类。
Q:
List<? super Child> list = new ArrayList<Parent>();
这个list有什么特点?
下面谁会报错
list.add(new Child())
list.add(new Parent())
Parent a= list.get();
Child b = list.get()
A:截图如下:

- Child c = list.get() 或者Parent p = list.get()所做的操作是在返回时, 把内部的<? super Child> 强转成外部的Parent或者child, 是不合理的, 因为编译器觉得child的父类 不一定 能转成parent或者child,所以禁止了这种行为( 比如parent的父类是object, 但object不一定就能转成parent或者child)。*list.add(new Child())所做的操作是在输入时, 把外部的child或者parent转成内部的<? super Child>, 这是合理的,因为child和parent一定能转成child的父类。
Q:
List<?> list = new ArrayList<A>();
这个list有什么特点?
A:get和add都不行,只能做remove等无返回值无输入A的操作。
PS: 注意,不是说不能调用get或add方法, 而是调用get或add时,不能使用A这个对象去操作。
即无法做add(A) 或者 A a = get(0)
但是可以做add(object) 或者Object o = get(0)
因为?可以转为Object, 但是无法转为A。
Q:下面这个代码会报错吗?
List<Fruit> fruitList = new ArrayList<>();
fruitList.add(new Fruit());
List<Apple> appleList = new ArrayList<>();
appleList.add(new Apple());
fruitList.addAll(appleList);
System.out.println(fruitList);
A:不会报错。会正常打印结果。

PECS原则
注意PECS原则和上面的区别!
上面之前提到的? extend或者? supert, 都是在声明对象的时候用的。
而PECS原则是用于泛型对象的方法输入参数!
假设有一个类定义如下:
public static class MyList<T> {
List<T> list = new ArrayList<>();
// 把输入参数塞给自己,类似于生产操作
public void pushList(List<T> t) {
list.addAll(t);
}
// 把自己的内容塞给输入参数,类似于让输入参数做消费。
public void pollList(List<T> t) {
t.addAll(list);
}
}
则T就是泛型参数。
Q:下面代码能正常运行吗?
MyList<Number> myList = new MyList<>(); List<Integer> intList = new ArrayList<>();
myList.pushList(intList); List<Object> objectList = new ArrayList<>();
myList.pollList(objectList);
A:不能正常运行, pushList和pollList都会报错
因为编译器检查后,认为 List<Integer>和List<Number>不是一个东西!
Q: 如果上文要支持pushList,应该怎么修改pushList方法的定义?
A:改成这样:
// 把输入参数塞给自己,类似于生产操作
public void pushList(List<? extends T> t) {
list.addAll(t);
}
即编译器认为,List<Integer> 和List<? extend Number>是一个东西,允许!
Q: 如果要支持pollList,怎么修改定义?
A:
// 把自己的内容塞给输入参数,类似于让输入参数做消费。
public void pollList(List<? super T> t) {
t.addAll(list);
}
因为是把自己的东西塞给输入参数, 而想要能塞进去,必须保证自己这个T,是输入参数的子类,反过来说,输入参数必须是T的父类,所以用super
于是编译器认为,List<Object> 和List<? super Number>是一个东西,允许!
PECS原则出自Effective Java, 注意只是一个编程建议而已!
- 如果有一个类A,泛型参数为T
- 如果他一般只用于接收输入容器List后,塞入自己内部的T容器, 则类A就叫生产者, 因此输入参数最好定义为<? extend T>最好, 以便能接收任何T子类的容器。
- 如果他一般只用于接收输入容器后List, 把自己内部的T元素塞给它, 那么这个类A就叫消费者, 输入参数最好定义为<? super T>\ 最好, 以便自己的T元素能塞给任何T元素的父类容器。
本文分享自华为云社区《15个问题掌握java泛型》,原文作者:breakDraw 。
15个问题告诉你如何使用Java泛型的更多相关文章
- Java 泛型(Generics) 综述
一. 引子 一般的类和方法.仅仅能使用详细类型:要么是基本类型.要么是自己定义类型.假设要编写能够应用于多种类型的代码,这样的刻板的限制对代码的束缚就会非常大. 多态算是一种泛化机制,但对代码的约束还 ...
- Java泛型概述
泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除. 泛型基础 泛型类 我们首先定义 ...
- Java泛型详解(转)
文章转自 importNew:Java 泛型详解 引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理 ...
- 深入理解什么是Java泛型?泛型怎么使用?【纯转】
本篇文章给大家带来的内容是介绍深入理解什么是Java泛型?泛型怎么使用?有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所助. 一.什么是泛型 “泛型” 意味着编写的代码可以被不同类型的对象所 ...
- Java基础系列二:Java泛型
该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 一.泛型概述 1.定 ...
- Java——Java泛型
该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 一.泛型概述 1.定 ...
- 面试阿里,首先要掌握的 Java 泛型,帮你一次性搞懂!
引言 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用.本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除. 泛型基础 泛型类 我们首 ...
- 【Java心得总结四】Java泛型下——万恶的擦除
一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...
- Java泛型总结
1. 什么是泛型?泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的 ...
随机推荐
- Vue学习笔记-nodejs+vue-cli4+webpack按装配置+项目创建
一 使用环境: windows 7 64位操作系统 二 Vue学习-nodejs按装配置,Node.js 就是运行在服务端的 JavaScript. 1. 去nodejs的官网下载 https: ...
- 从HashMap面试聊聊互联网内卷
微信公众号:大黄奔跑 关注我,可了解更多有趣的面试相关问题. 写在之前 毫无疑问,回想2020年有什么词出现在眼前最多的,无疑是"996"和"内卷",从马老师的 ...
- 百度AI api使用
# *********************************baidu-api-通用文字识别******************************************** # im ...
- 如何掌握 C 语言的一大利器——指针?
一览:初学 C 语言时,大家肯定都被指针这个概念折磨过,一会指向这里.一会指向那里,最后把自己给指晕了.本文从一些基本的概念开始介绍指针的基本使用. 内存 考虑到初学 C 语言时,大家可能对计算机的组 ...
- pyinstaller打包exe运行失败
使用Pyinstaller来打包自己开发的软件时遇到的几个问题及解决方法.工具主要功能是数据分析,使用机器学习算法完成数据训练和预测功能.主要用到了两个学习库keras和sklearn,所以说在打包时 ...
- 《PYTHON机器学习及实践-从零开始通往KAGGLE竞赛之路》 分享下载
转: <PYTHON机器学习及实践-从零开始通往KAGGLE竞赛之路> 分享下载 书籍信息 书名: PYTHON机器学习及实践-从零开始通往KAGGLE竞赛之路 标签: PYTHON机器学 ...
- CodeBlocks的安装配置以及使用教程
CodeBlocks的安装配置以及使用教程 教程写的很啰嗦,本来几句话就能搞定的,但为了照顾到那部分真正的小白还请大家见谅! 一.下载 前往CodeBlocks官网下载带编译器的版本,目前的最新版本为 ...
- Java的特性和优势以及不同版本的分类,jdk,jre,jvm的联系与区别,javadoc的生成
Java 1.Java的特性和优势 Write Once,Run Anywhere 简单性 面向对象 可移植性 高性能 分布式 动态性 多线程 安全性 健壮性 2.Java的三大版本 JavaSE:标 ...
- docker搭建redis集群和Sentinel,实现故障转移
0.引言 公司开发需要用到redis,虽然有运维自动搭建,还是记录下如何搭建redis集群和Sentinel. 采用的是vagrant虚拟机+docker的方式进行搭建. 搭建思路: 首先是借鉴下其他 ...
- xss和实体编码的一点小思考
首先,浏览器渲染分以下几步: 解析HTML生成DOM树. 解析CSS生成CSSOM规则树. 将DOM树与CSSOM规则树合并在一起生成渲染树. 遍历渲染树开始布局,计算每个节点的位置大小信息. 将渲染 ...