Java集合与泛型中的陷阱
List,List<Object>区别
List<Integer> t1 = new ArrayList<>();
// 编译通过
List t2 = t1;
//编译失败
List<Object> t3 = t1;
t1 可以赋给 t2, 但是 t1 不能赋给 t3,会抛出如下异常
Error:(16, 35) java: 不兼容的类型: java.util.List<java.lang.Integer>无法转换为java.util.List<java.lang.Object>
List<?>注意点
List<Object> t1 = new ArrayList<>();
List<?> t2 = t1;
// 编译通过
t2.remove(0);
t2.clear();
// 编译不通过
t2.add(new Object());
List<?> 是一个泛型,在没有赋值之前,是可以接受任何集合的赋值的,但是请注意,赋值之后就不能往里面添加元素了
提示如下错误:
Error:(18, 19) java: 对于add(java.lang.Object), 找不到合适的方法
方法 java.util.Collection.add(capture#1, 共 ?)不适用
(参数不匹配; java.lang.Object无法转换为capture#1, 共 ?)
方法 java.util.List.add(capture#1, 共 ?)不适用
(参数不匹配; java.lang.Object无法转换为capture#1, 共 ?)
所以 List<?> 一般用来作为参数来接受外部的集合,或者返回一个不知道具体元素的集合。
<? extends T> 与 <? super T>
<? extends T>
<? extends T> a,a 这个变量可以接受 T 及其 T 子类的集合,上界为 T,并且从 a 取出来的类型都会被强制转换为 T
class Animal{
}
class Cat extends Animal{
}
class RedCat extends Cat{
}
demo:
List<Animal> animals = new ArrayList<>();
List<Cat> cats = new ArrayList<>();
List<RedCat> redCats = new ArrayList<>();
// 可以通过编译
List<? extends Cat> extendsCat = redCats;
// 不能通过编译,因为只能接受 Cat 及其子类的集合
extendsCat = animals;
// 重点注意:下面三行都不能通过编译
extendsCat.add(new Animal());
extendsCat.add(new Cat());
extendsCat.add(new RedCat());
// 重点注意:可以通过编译
extendsCat.add(null);
<? extends T>最需要注意的是,就是不能向里面添加除null之外的其他所有元素,这个和 List<?> 有点类似
<? super T>
<? super T>,它和 <? extends T> 有点相反。**对于 <? super T> a**,a 这个变量可以接受 T 及其 T 父类的集合,下界为 T,并且从 a 取出来的类型都会被强制转换为 Object
demo:
List<Animal> animals = new ArrayList<>();
List<Cat> cats = new ArrayList<>();
List<RedCat> redCats = new ArrayList<>();
// 可以通过编译
List<? super Cat> superCat = animals;
// 不能通过编译,因为只能接受 Cat 及其父类的集合
superCat = redCats;
// 重点注意:不能通过编译,只能添加 Cat 及其 Cat 的子类
superCat.add(new Animal());
// 重点注意,可以通过编译
superCat.add(new Cat());
superCat.add(new RedCat());
superCat.add(null);
注意,<? super T>最需要注意的是,在虽然可以接受 T 及其父类的赋值,但是只能向里面添加 T 及其 T 的子类。
总结
1、List<? extends T> a ,可以把 a 及其 a 的子类赋给 a,从 a 里取的元素都会被强制转换为 T 类型,不过需要注意的是,不能向 a 添加任何除 null 外是元素。
2、List<? super T> a ,可以把 a 及其 a 的父类赋给 a,从 a 里取的元素都会被强制转换为 Object 类型,不过需要注意的是,可以向 a 添加元素,但添加的只能是 T 及其子类元素。
List泛型与重载
你觉得下面这道题能够编译通过吗?
class GernerTypes {
public static void method(List<Integer> list) {
System.out.println("List<Integer> list");
}
public static void method(List<String> list) {
System.out.println("List<String> list");
}
}
不通过编译,错误信息:
Error:(20, 28) java: 名称冲突: method(java.util.List<java.lang.String>)和method(java.util.List<java.lang.Integer>)具有相同疑符
两个方法的参数不同,为什么会重载不通过呢?
实际上在 Java 的泛型中,泛型只存在于源码中,在编译后的字节码中,泛型已经被替换为原生类型了,并且在相应的地方插入了强制转换的代码。
所以上面的两个方法,看似参数不一样,但是经过编译擦出之后,他们的参数就是一样的了,所以编译不通过。
数组集合转换:
String[] arr = {"one", "two", "three"};
// 数组转换成集合
List<String> list = Arrays.asList(arr);
// 向集合添加元素:编译正常,但运行时抛出了异常
list.add("four");
运行时报错:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at com.qhong.basic.list.test.main(test.java:16)
问题来了,向集合添加元素为啥会抛出异常呢??
我们先来看一下 Arrays.asList(arr) 方法究竟返回了什么?
看源码:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
/**
* @serial include
*/
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
。。。。
返回的List内部直接引用了原数组arr
原数组长度固定为3,所以不可以再add
下面的代码证明这一点
String[] arr = {"one", "two", "three"};
// 数组转换成集合
List<String> list = Arrays.asList(arr);
// 修改 arr
arr[0] = "0";
//打印看看
System.out.println(list.get(0));
打印:
0
建议大家这样转换比较安全
List<String> list = new ArrayList<>(Arrays.asList(arr));
参考:
Java集合与泛型中的陷阱的更多相关文章
- Java集合与泛型中的几个陷阱,你掉进了几个?
下面我总结了集合.泛型.数组转集合等一些常见的陷进,认真看完,相信你绝对有所收获. 1.List ,List<?> 与 List<Object> 有区别吗? 说实话,我敢保证很 ...
- Java集合之泛型的使用
Java集合之泛型的使用 泛型提供了一种轻便灵活的数据操作,数据的安全性相对提高. 泛型提供了对列表元素的约束条件,比如ArrayList有序链表,可存储任意类型的元素. 此处构建一个ArrayLis ...
- 浅入深出之Java集合框架(中)
Java中的集合框架(中) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...
- Java进阶4表达式中的陷阱
Java进阶4表达式中的陷阱 20131103 表达式是Java中最基本的组成单元,各种表达式是Java程序员最司空见惯的内容,Java中的表达式并不是十分的复杂,但是也有一些陷阱.例如当程序中使用算 ...
- Java集合和泛型
集合 常用的集合有ArrayList,TreeSet,HashMap,HashSet. ArrayList 最常用的集合,每次插入都在后面追加元素. TreeSet 以有序状态保持并可防止重复.当你需 ...
- Java 集合和泛型
一.集合(Collections) Java使用集合来组织和管理对象. 1.Java的集合类 集合类主要负责保存.盛装和管理对象,因此集合类也被称为容器类. 集合类分为Set.List.Map和Que ...
- java——集合、泛型、ArrayList、LinkedList、foreach循环、模拟ktv点歌系统
集合:一系列特殊的类,这些类可以存储任意类型的对象,长度可变,集合类都在java.util包中. 但是集合记不住对象的类型,当把对象从集合中取出时这个对象的编译类型就变成了Object类型.这样在取元 ...
- Java 集合框架_中
Set接口 特点: [1]Set接口表示一个唯一.无序的容器(和添加顺序无关) Set接口常用实现类有 HashSet [1]HashSet是Set接口的实现类,底层数据结构是哈希表. [2]Hash ...
- java集合示例 小心重载的陷阱
package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springframework. ...
随机推荐
- linux自定义开机自启多个服务的脚本
linux服务器重启后,每次要启动redis.ftp.tomcat等应用总是很麻烦,于是写了一个自定义脚本,在开机或重启的时候,自动启动多个服务.应用. 很简单,写脚本.设置开机启动. 第一步.准 ...
- EM(Expectation Maximization )
概括 看李航老师的<统计学习方法>知道,EM是一个对于有隐含随机变量的概率模型的参数的估计方法,它是一种无监督的算法. 只是有些重要的点并没有给出, 比如没有三硬币例子中直接给出的 u(z ...
- opencart3产品页调用upc/数量等信息
opencart3产品页默认只调用标题.价格.型号等几个数据,如果想要调用更多的参数要如何操作呢?跟着ytkah一起来看看吧.首先打开/catalog/model/catalog/product.ph ...
- Linux下安装scikit-learn
Linux下安装scikit-learn sudo apt-get install python-pip sudo apt-get install python-pandas python-sympy ...
- MFC关于.rc文件 .rc2文件
.rc文件和.rc2文件 c和rc2都是资源文件,包含了应用程序中用到的所有的资源. 两者不同在于:rc文件中的资源可以直接在VC集成环境中以可视化的方法进行编辑和修改; 而rc2中的资源不能在VC的 ...
- 用微信小程序连接leancloud数据库注意事项~
具体步骤转载如下: 官网教程 大佬提示 注意事项: 1.下载的av-weapp-min.js,需要放在当前项目名称的子目录pages下 2.如上述教程,需要注册leancloud和AppID,并写在a ...
- 关于Linux目录结构的理解
dUI与刚接触Linux的学习者来说,那么多的根下目录足够让我们头疼不已,如下图: 那么对于初学者来说,我们首要了解的是哪些目录呢? 就是这个标黄绿色的tmp目录,此目录是一个存放临时文件夹的目录( ...
- C#中DataTable与XML格式的相互转换
1.DataTable转换成XML public string ConvertDataTableToXML(DataTable xmlDS) { MemoryStream stream = null; ...
- 18.12.09-C语言练习:黑洞数 / Kaprekar问题
题目: 程序: #include <stdio.h> int main(void) { int n, a, b, c, t, A, B; printf("输入一个三位数整数:&q ...
- OpenStack-Neutron-VPNaaS-代码
目前juno只支持ipsec的vpn 但是其实稍微修改代码pptp/openvpn/gre也都是可以支持的,下面看看vpn服务的代码流程: 默认我们创建好了ide策略.ipsec策略和vpn服务,因 ...