List、List&#60Object&#62、List&#60?&#62的区别以及用法

本文详细介绍了Java中List、List<Object>和List<?>的区别,强调了泛型在集合操作中的作用。List没有泛型限制,可添加任何类型元素。List<Object>限制了指向的集合对象必须是Object类型,但添加元素无类型限制。List<?>则表示不确定类型,不能添加元素,但可以获取元素并调用其Object方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文尽量减少代码,多讲道理,笔者最不喜欢上来就罗列一大堆代码的技术文章,实在让人难有耐心看下去,如果你愿意耐心读这篇文章,那一定会对你有帮助。
欢迎转载,但是请务必注明出处(不要直接把我图扣走~~)。
区别三者之前需要知道:
1、对集合进行操作(例如:add()),看的是集合声明时所指定的泛型,而不是其所指向的集合对象(堆内存中的对象)所指定的泛型。
2、集合中存放的是元素的引用(地址),并非元素本身。
3、如果A是B的子类,List<A>并不是List<B>的子类(与数组不同)。

1、List

1、声明的List集合对其 所指向的集合对象(就是赋值的集合对象)的限制:无泛型限制,并且无视指向的集合对象的泛型,直接当成List<Object>处理(泛型擦除)
2、对用List声明的集合进行添加的元素的限制:无类型限制,也就是只要是Object就行

// new ArrayList<Integer>()是list指向的对象
ArrayList list = new ArrayList<Integer>();

泛型参数Integer对集合list无任何影响!list直接无视Integer!
并且list的泛型类型为默认的Object(泛型擦除)

list.add(new String("测试"));

String对象是Object对象,可添加

//编译器认为list.get(0)是Object类型,所以当然提示找不到length()方法
list.get(0).length(); × 

提示Object中无方法length()
可见编译器认为list中所有的元素都是Object,不知道集合元素具体类型

//编译器认为list.get(0)是Object类型,并且Object中有getClass()方法
//编译器可以通过检查,但是实际上调用getClass()时,是在运行阶段,此时
//程序已经准确地取出(指向)了new String("测试")
list.get(0).getClass();

getClass()为Object方法,编译自然可以通过
但是!输出类型并不是 java.lang.Object而是 java.lang.String!
编译器无法准确知道集合元素具体类型,但是运行的时候,是直接拿元素真实的的对象来调用getClass()方法,当然能获取元素准确类型
在这里插入图片描述

2、List<Object>

1、声明的List<Object> 集合对其 所指向的集合对象(就是赋值的集合对象)的限制:泛型必须是Object,即必须是ArrayList<Object> 、LinkedList<Object> …
2、对用List<Object> 声明的集合进行添加的元素的限制:无类型限制,也就是只要是Object就行

//ArrayList<Integer>对象并不是 ArrayList<Object>对象。
ArrayList<Object> list = new ArrayList<Integer>();	×  

虽然Integer对象是Object对象
但是 ArrayList<Integer>对象并不是 ArrayList<Object>对象。
List<Object> 与List的用法区别就在这里,
编译时:
集合进行赋值操作时,List不用进行泛型检查(即便最终它默认泛型为Object);
而List<Object> 要进行泛型检查(泛型类型只能为Object)。
余下的List<Object> 与List一样

ArrayList<Object> list = new ArrayList<Object>();
list.add(new String("测试"));
list.get(0).length();	× 
list.get(0).getClass();

在这里插入图片描述

3、List<?>

1、声明的List<Object> 集合对其 所指向的集合对象(就是赋值的集合对象)的限制:无泛型限制,因为?(占位符)代表一个不确定类型(并不是代表Object),即能代表所有类型
2、对用List<Object> 声明的集合进行添加的元素的限制:无不可对其进行添加任何类型元素,因为在编译阶段无法知道其准确的泛型类型,随意add()方法无法通过编译检查。

ArrayList<?> list = new ArrayList<Integer>();

ArrayList<Integer>对象是ArrayList<?>对象的子类

list.add(new String("测试"));	× 

程序在编译阶段无法得知list的泛型类型,也不会把添加的元素当成Object处理,所以无法添加元素。
既然List<?>的对象无法添加元素那就让它指向一个已经有含元素的集合,以进行后续实验:

//创建一个已经有含元素的集合
ArrayList<String> listInt = new ArrayList<String>();	√
listInt.add(new String("测试"));//List<?> list对指向的集合对象无泛型限制,所以当然可以让它指向listInt
List<?> list = listInt;
//编译器并不知道list.get(0)的类型,所以当然提示找不到length()方法
list.get(0).length();	× 

此处也会提示Object中无方法length()
但是这里并不是把list中元素当成Object,而是,尽管编译器不知道list中元素的具体类型,但是至少该元素有Object中的方法!所以才会有这样的提示(我认为这个提示并不好),至于为什么知道编译器并没有把其中元素当成Object处理,继续往下看。

//不兼容的类型: CAP#1无法转换为String
String str = list.get(0);	× 

这里错误提示的是:不兼容的类型: CAP#1无法转换为String
而不是:不兼容的类型: Object无法转换为String
尽管list.get(0)引用的确实是String类型但是编译器只知道他是一个不确定类型(CAP#1)

Object str = list.get(0);

这行代码是正确的,但是不能因此证明list.get(0)类型为Object,因为任何引用类型都可以自动向上转型为Object

// java.lang.String
list.get(0).getClass();

与List、List<Object>一样,调用list.get(0)可以获取元素准确类型String
在这里插入图片描述

理解泛型的用法关键在于理解编译器的泛型检查机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值