Collection(单列集合)、Map(双列)
一、Collection集合
- 集合:集合是java中提供的一种容器,可以用来存储多个引用数据类型的数据。
集合和数组既然都是容器,它们有什么区别呢?
- 数组的长度是固定的。集合的长度是可变的。
- 集合存储的都是引用数据类型。如果想存储基本类型数据需要存储对应的包装类类型。
单列集合常用类的继承体系:
Collection集合:接口,是所有单列集合的顶层父接口,该集合中的方法可以被所有单列集合共享
List集合: 接口,元素可重复,元素存取有序,元素有索引
ArrayList集合: 实现类,查询快,增删慢
LinkedList集合: 实现类,查询慢,增删快
Set集合: 接口, 元素不可重复(唯一),元素无索引
HashSet集合: 实现类,元素存取无序
LinkedHashSet集合:实现类,元素存取有序
TreeSet集合:实现类,可以对集合中的元素进行排序
1.1 Collection 常用功能
Collection<E> 是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。方法如下:
public boolean add(E e)
: 把给定的对象添加到当前集合中 。public void clear()
:清空集合中所有的元素。public boolean remove(E e)
: 把给定的对象在当前集合中删除。public boolean contains(Object obj)
: 判断当前集合中是否包含给定的对象。public boolean isEmpty()
: 判断当前集合是否为空。public int size()
: 返回集合中元素的个数。public Object[] toArray()
: 把集合中的元素,存储到数组中
tips: 有关Collection中的方法可不止上面这些,其他方法可以自行查看API学习。
default Stream<E> stream() //返回以此集合为源的顺序Stream
default Stream<E> parallelStream() //以此集合为源返回可能并行的Stream 。 此方法允许返回顺序流。
1.2 Iterable
Iterable接口的概述
java.lang.Iterable
实现这个接口允许一个对象作为“for-each循环”语句的目标。
Iterable接口常用方法
default void forEach(Consumer<? super T> action) //对Iterable中的每个元素执行给定的操作,直到所有元素都被处理完或该操作抛出异常。
二、Iterator迭代器
在程序开发中,经常需要遍历单列集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator
。
2.1 迭代的概念
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
2.2 获取迭代器对象
Collection集合提供了一个获取迭代器的方法:
public Iterator iterator()
: 获取集合对应的迭代器,用来遍历集合中的元素的。
2.3 Iterator<E>接口的常用方法
public E next()
:返回迭代的下一个元素。public boolean hasNext()
:如果仍有元素可以迭代,则返回 true。
default void remove()
2.4 迭代器的常见问题
常见问题一
- 在进行集合元素获取时,如果集合中已经没有元素可以迭代了,还继续使用迭代器的next方法,将会抛出java.util.NoSuchElementException没有集合元素异常。
解决办法: 如果还需要重新迭代,那么就重新获取一个新的迭代器对象进行操作
常见问题二
- 在进行集合元素迭代时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出ConcurrentModificationException并发修改异常.
但可以使用迭代器的remove() 方法删除元素
2.5 迭代器的实现原理
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
2.6 增强for
增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
for(元素的数据类型 变量 : Collection集合or数组){
//写操作代码
}
它用于遍历Collection和数组。通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* @Author:pengzhilin
* @Date: 2020/9/13 10:09
*/
public class Test {
public static void main(String[] args) {
/*
概述:增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。
它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
格式:
for(元素的数据类型 变量名 : 数组名\集合名){
}
*/
// 创建Collection集合对象,限制集合中元素的类型为String
Collection<String> col = new ArrayList<>();
// 往col集合中添加元素
col.add("AAA");
col.add("BBB");
col.add("CCC");
col.add("DDD");
// 增强for循环遍历
for (String e : col) {
System.out.println(e);
}
System.out.println("======================================");
String[] arr = {"AAA",
"BBB",
"CCC",
"DDD"};
for (String e : arr){
System.out.println(e);
}
System.out.println("======================================");
// 增强for循环快捷键: 数组名\集合名.for
for (String s : col) {
System.out.println(s);
}
System.out.println("=======================================");
for (String s : arr) {
System.out.println(s);
}
System.out.println("=======================================");
Iterator<String> it = col.iterator();
// 迭代器快捷键: itit 回车
while (it.hasNext()) {
String next = it.next();
System.out.println(next);
}
System.out.println("=======================================");
// 在遍历的过程中,不能对集合中的元素进行增删操作。
/*for (String s : col) {
if (s.equals("李冰冰")) {
col.remove(s);
}
}*/
}
}
tips:
增强for循环必须有被遍历的目标,目标只能是Collection或者是数组;
增强for(迭代器)仅仅作为遍历操作出现,不能对集合进行增删元素操作,否则抛出ConcurrentModificationException并发修改异常
三、List接口
List接口的概述
java.util.List
接口继承自Collection
接口,是单列集合的一个重要分支,习惯性地会将实现了List
接口的对象称为List集合。
在Collection中,List集合是有序的,Developer可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素。
List是一个接口:
public interface List<E> extends Collection<E>{...}
List接口特点
- 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)。
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
- 集合中可以有重复的元素。
tips:List接口的子类java.util.ArrayList类,该类中的方法都是来自List中定义。
List接口新增常用方法
List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:
public void add(int index, E element)
: 将指定的元素,添加到该集合中的指定位置上。public E get(int index)
:返回集合中指定位置的元素。public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
List集合特有的方法都是跟索引相关
List的子类
ArrayList集合
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。
LinkedList集合
java.util.LinkedList
集合数据存储的结构是链表结构。方便元素添加、删除的集合。
LinkedList是一个双向链表,那么双向链表是什么样子的呢,我们用个图了解下
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。
public void addFirst(E e)
:将指定元素插入此列表的开头。public void addLast(E e)
:将指定元素添加到此列表的结尾。public E getFirst()
:返回此列表的第一个元素。public E getLast()
:返回此列表的最后一个元素。public E removeFirst()
:移除并返回此列表的第一个元素。public E removeLast()
:移除并返回此列表的最后一个元素。public E pop()
:从此列表所表示的堆栈处弹出一个元素。相当于removeFirst()public void push(E e)
:将元素推入此列表所表示的堆栈。相当于addFirst(E e)
LinkedList是List的子类,List中的方法LinkedList都是可以使用,在开发时,LinkedList集合也可以作为堆栈,队列的结构使用。
================================================================
3.2、List 列表补充
ArrayList是最常用的一种List的子类(当然也实现了其他接口,也继承了父类)。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{...}
在List集合中,我们常用到ArrayList和LinkedList这两个类。
其中,ArrayList底层通过数组实现,随着元素的增加而动态扩容。而LinkedList底层通过链表来实现,随着元素的增加不断向链表的后端增加节点。
ArrayList用法类似于数组,且其容量可按需要动态调整,亦被称为动态数组。
数组最大的痛点是大小固定(可以改变,但是很麻烦)
ArrayList底层是用数组实现的,所以名字里带了个数组(Array)。
ArrayList使用数组方式存储数据,所以根据索引查询数据速度快,而新增或者删除元素时需要设计到位移操作,所以比较慢。
LinkedList使用双向链表方式存储数据,每个元素都记录前后元素的指针,所以插入、删除数据时只是更改前后元素的指针指向即可,速度非常快。然后通过下标查询元素时需要从头开始索引,所以比较慢,但是如果查询前几个元素或后几个元素速度比较快。
1、Map 映射
映射(Map) 是一种键-值对(key-value)集合,
Map 集合中的每一个元素都包含一个键对象和一个值对象。其中,键对象不允许重复,而值对象可以重复,并且值对象还可以是 Map 类型的,就像数组中的元素还可以是数组一样。
Map 接口主要有两个实现类:HashMap 类和 TreeMap 类。其中,HashMap 类按哈希算法来存取键对象,而 TreeMap 类可以对键对象进行排序。
Map接口的常用方法
方法名称 | 说明 |
---|---|
V get(Object key) | 返回 Map 集合中指定键对象所对应的值。V 表示值的数据类型 |
V put(K key, V value) | 向 Map 集合中添加键-值对,返回 key 以前对应的 value,如果没有, 则返回 null |
V remove(Object key) | 从 Map 集合中删除 key 对应的键-值对,返回 key 对应的 value,如果没有,则返回null |
Set entrySet() | 返回 Map 集合中所有键-值对的 Set 集合,此 Set 集合中元素的数据类型为 Map.Entry |
Set keySet() | 返回 Map 集合中所有键对象的 Set 集合 |
注意:TreeMap 类的使用方法与 HashMap 类相同,唯一不同的是 TreeMap 类可以对键对象进行排序
指定了参数类型编译器在编译期间就会帮助你检查存入容器的对象是不是参数类型!不是就会报错!保证了类型安全!性能上没什么影响,因为泛型在运行期间会擦除!就是说用不用类型参数在运行期间编译后的运行代码是一样的!
Map map = new HashMap();
Map<String,String> map1 =new HashMap<String,String>();
Map<String,Integer> map2 =new HashMap<String,Integer>();
System.out.println(map.getClass().equals(map1.getClass()));
System.out.println(map.getClass().equals(map2.getClass()));
System.out.println(map2.getClass().equals(map1.getClass()));
返回结果全为true;说明他们运行的是同一份字节码!
=======================================
四、集合工具类Collections
Java中的Collections类(工具类)常用方法 总结
-
java.utils.Collections
是集合工具类,用来对集合进行操作。常用方法如下:
-
public static void shuffle(List<?> list)
:打乱集合顺序。随机打乱 -
public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。元素实现Comparable -
public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。
public class Student implements Comparable<Student>{
int age;
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
// 指定排序规则
// 前减后 升序
// 后减前 降序
// 前:this 后: 参数o
return this.age - o.age;// 升序
}
}
//------------
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test2_sort {
public static void main(String[] args) {
/*
Collections常用功能:
public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
默认规则: 事先写好的规则
排序规则: 集合元素所属的类一定要实现Comparable接口,重写compareTo方法,在compareTo方法中指定排序规则
*/
// 创建List集合,限制集合中元素的类型为Integer类型
List<Integer> list = new ArrayList<>();
// 往集合中添加元素
list.add(300);
list.add(100);
list.add(200);
list.add(500);
list.add(400);
System.out.println("排序之前的集合:"+list); // [300, 100, 200, 500, 400]
// 将集合中元素按照默认规则排序
Collections.sort(list);
System.out.println("排序之后的集合:"+list); // [100, 200, 300, 400, 500]
System.out.println("=========================================");
// 创建List集合,限制集合中元素的类型为Student类型
List<Student> list1 = new ArrayList<>();
// 往集合中添加元素
Student stu1 = new Student(19);
Student stu2 = new Student(18);
Student stu3 = new Student(20);
Student stu4 = new Student(17);
list1.add(stu1);
list1.add(stu2);
list1.add(stu3);
list1.add(stu4);
System.out.println("排序之前的集合:"+list1);
// 将集合中元素按照默认规则排序
Collections.sort(list1);
System.out.println("排序之后的集合:"+list1);
}
}
public class Test3_sort {
public static void main(String[] args) {
/*
Collections常用功能:
public static <T> void sort(List<T> list,Comparator<? super T> com):将集合中元素按照指定规则排序。
参数Comparator: 就是用来指定排序规则的
通过Comparator接口中的compare方法来指定排序规则
*/
// 创建List集合,限制集合中元素的类型为Integer类型
List<Integer> list = new ArrayList<>();
// 往集合中添加元素
list.add(300);
list.add(100);
list.add(200);
list.add(500);
list.add(400);
System.out.println("排序之前的集合:" + list); // [300, 100, 200, 500, 400]
// 将集合中元素按照指定规则排序---->降序
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// 指定排序规则
// 前减后 升序
// 后减前 降序
// 前: 第一个参数o1 后:第二个参数o2
return o2 - o1;
}
});
System.out.println("排序之后的集合:" + list); // [500, 400, 300, 200, 100]
// 将集合中元素按照指定规则排序---->升序
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
System.out.println("排序之后的集合:" + list);// [100, 200, 300, 400, 500]
System.out.println("=======================================");
// 创建List集合,限制集合中元素的类型为Student类型
List<Student> list1 = new ArrayList<>();
// 往集合中添加元素
Student stu1 = new Student(19);
Student stu2 = new Student(18);
Student stu3 = new Student(20);
Student stu4 = new Student(17);
list1.add(stu1);
list1.add(stu2);
list1.add(stu3);
list1.add(stu4);
System.out.println("排序之前的集合:" + list1);
// 将集合中元素按照指定规则排序-->按照年龄降序排序
Collections.sort(list1, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 指定排序规则
// 前减后 升序
// 后减前 降序
// 前: 第一个参数o1 后:第二个参数o2
return o2.age - o1.age;
}
});
System.out.println("排序之后的集合:" + list1);
// 将集合中元素按照指定规则排序-->按照年龄升序排序
Collections.sort(list1, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 指定排序规则
// 前减后 升序
// 后减前 降序
// 前: 第一个参数o1 后:第二个参数o2
return o1.age - o2.age;
}
});
System.out.println("排序之后的集合:" + list1);
}
}
可变参数
可变参数的使用
在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化.
格式:
修饰符 返回值类型 方法名(参数类型... 形参名){ }
public class Test1 {
public static void main(String[] args) {
/*
可变参数:
概述:在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化.
格式:
修饰符 返回值类型 方法名(数据类型... 变量名){}
*/
/* method1(10,20,30,40,50);
int[] arr = {10,20,30,40,50};
method2(arr);*/
/*method3();
method3(10,20,30,40);*/
method3(10,20,30,40,50);
/* int[] arr = {10,20,30,40,50};
method3(arr);*/
}
// 定义一个方法,可以接收5个int类型的数
public static void method3(int... nums){ //可以单个或多个int数据接收,也可以int数组接收,还可以不传参
// 使用:把nums可变参数当成数组使用
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
}
// 定义一个方法,可以接收5个int类型的数
public static void method2(int[] arr){// 接收数组
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
// 定义一个方法,可以接收5个int类型的数
public static void method1(int num1,int num2,int num3,int num4,int num5){// 接收5个具体的数
}
}
注意事项
1.一个方法只能有一个可变参数
2.如果方法中有多个参数,可变参数要放到最后。
应用场景: Collections
在Collections中也提供了添加一些元素方法:
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。
import java.util.ArrayList;
import java.util.Collections;
public class Test3 {
public static void main(String[] args) {
/*
应用场景: Collections
在Collections中也提供了添加一些元素方法:
public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。
*/
// 创建ArrayList集合,限制集合元素的类型为String类型
ArrayList<String> list = new ArrayList<>();
// 往list集合中添加批量元素
Collections.addAll(list,"2","A","K","Q","J","10","9","8","7","6","5","4","3");
System.out.println(list);
}
}
五、泛型
泛型的作用:
集合不使用泛型:
集合不使用泛型的时候,存的时候什么类型都能存。但是取的时候就懵逼了。取出来啥也不是。
使用泛型
使用泛型在编译期直接对类型作出了控制,只能存储泛型定义的数据
泛型:定义的时候表示一种未知的数据类型,在使用的时候确定其具体的数据类型。
tips:泛型的作用是在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
5.1 定义和使用含有泛型的类
定义含有泛型的类
定义格式:
修饰符 class 类名<泛型变量> {
}
泛型变量: 可以是任意字母 例如: T,E...
泛型在定义的时候不具体类型,使用的时候才具体类型。在使用的时候确定泛型的具体数据类型。
class ArrayList<E>{
public boolean add(E e){ }
public E get(int index){ }
....
}
确定泛型具体类型
在创建对象的时候确定泛型
例如,ArrayList<String> list = new ArrayList<String>();
此时,变量E的值就是String类型,那么我们的类型就可以理解为:
class ArrayList<String>{
public boolean add(String e){ }
public String get(int index){ }
...
}
public class MyArrayList<E> {
E e;
public E method(E e){
return e;
}
}
public class Test {
public static void main(String[] args) {
/*
定义含有泛型的类:
public class 类名<泛型变量>{
}
泛型变量的位置: 写任意字母,例如:A,B,C,D,E,...a,b,c,...一般会写E
使用含有泛型的类: 创建该类对象的时候,确定该类泛型的具体数据类型
什么时候定义泛型的类:
当类中的成员变量或者成员方法的形参类型\返回值类型不确定的时候,就可以把该类定义为含有泛型的类
*/
MyArrayList<String> list1 = new MyArrayList<>();
list1.e = "it";
String res1 = list1.method("itcast");
System.out.println("res1:"+res1);// itcast
System.out.println("=======================================");
MyArrayList<Integer> list2 = new MyArrayList<>();
list2.e = 100;
Integer res2 = list2.method(10);
System.out.println("res2:"+res2);// 10
}
}
5.2 定义和使用含有泛型的方法
定义含有泛型的方法
定义格式:
修饰符 <泛型变量> 返回值类型 方法名(参数){
}
例如,
public class Test {
// 定义含有泛型的方法
public static <T> T method1(T t){
return t;
}
}
确定泛型具体类型
调用方法时,确定泛型的类型
public class Test {
public static void main(String[] args) {
/*
定义含有泛型的方法:
修饰符 <泛型变量> 返回值类型 方法名(形参列表){
方法体
}
泛型变量: 任意字母 一般会写T,M,...
使用含有泛型的方法: 调用含有泛型方法的时候确定其泛型的具体数据类型
什么时候会定义含有泛型的方法:
如果一个类中,某个方法的参数类型或者返回值类型不确定的时候,可以把该方法定义为含有泛型的方法
*/
Integer i1 = method1(100);// 指定泛型的具体数据类型为Integer
System.out.println(i1);// 100
System.out.println("============================");
String s = method1("it");// 指定泛型的具体数据类型为String
System.out.println(s);// itheima
}
// 定义含有泛型的方法
public static <T> T method1(T t){
return t;
}
}
5.3 定义和使用含有泛型的接口
定义含有泛型的接口
定义格式:
修饰符 interface 接口名<代表泛型的变量> {
}
public interface IA<E> {
public abstract void method1(E e);
public default E method2(E e){
return e;
}
}
确定泛型具体类型
使用格式:
1、定义实现类时确定泛型的类型
// 通过实现类的方式确定接口泛型的具体数据类型
public class Imp1 implements IA<String> {
@Override
public void method1(String s) {
}
@Override
public String method2(String s) {
return null;
}
}
此时,泛型E的值就是String类型。
2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型
- 实现类实现接口:
// 实现类实现接口的时候不确定接口泛型的具体数据类型,
// 而是创建实现类对象的时候确定接口泛型的具体数据类型
public class Imp2<E> implements IA<E> {
@Override
public void method1(E e) {
System.out.println("实现类 method1");
}
@Override
public E method2(E e) {
return e;
}
}
确定泛型:
public class Test {
public static void main(String[] args) {
/*
定义含有泛型的接口:
public interface 接口名<泛型变量>{
}
泛型变量:任意字母,一般可以使用E
使用含有泛型的接口: 确定接口泛型的具体数据类型
1.通过实现类的方式确定接口泛型的具体数据类型
public class 类名 implements 接口名<具体的数据类型>{
}
2.实现类实现接口的时候不确定接口泛型的具体数据类型,
而是创建实现类对象的时候确定接口泛型的具体数据类型
public class 类名<泛型变量> implements 接口名<泛型变量>{
}
*/
// 创建实现类对象的时候确定接口泛型的具体数据类型
Imp2<String> imp1 = new Imp2<>();
imp1.method1("it");
String s1 = imp1.method2("itcast");
System.out.println(s1);// itcast
System.out.println("==========================");
Imp2<Integer> imp2 = new Imp2<>();
imp2.method1(100);
Integer i = imp2.method2(100);
System.out.println(i);// 100
}
}
5.4 泛型通配符
通配符基本使用
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
此时只能接受数据,不能往该集合中存储数据。
例如:
public class Test {
public static void main(String[] args) {
/*
通配符基本使用:
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
注意: 不能往该集合中存储数据,只能获取数据和删除数据
*/
// 关系:String继承Object,Integer继承Number,Number继承Objec
ArrayList<Object> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Integer> list3 = new ArrayList<>();
ArrayList<Number> list4 = new ArrayList<>();
list2.add("it");
//method1(list1);
method1(list2);
//method1(list3);
//method1(list4);
//method2(list1);
method2(list2);
//method2(list3);
//method2(list4);
// 泛型没有多态
//ArrayList<Object> list = new ArrayList<String>();// 编译报错
}
// 定义一个方法,可以接收以上4个集合
public static void method1(ArrayList list){
Object obj = list.get(0);
list.add("jack");
System.out.println("obj:"+obj);// it
System.out.println("list:"+list);// [it, jack]
}
public static void method2(ArrayList<?> list){
Object obj = list.get(0);
//list.add("jack");// 编译报错
System.out.println("obj:"+obj);// it
System.out.println("list:"+list);// [it]
}
}
通配符高级使用----受限泛型
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置。但是在JAVA的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
- 格式:
类型名称 <? extends 类 > 对象名称
- 意义:
只能接收该类型及其子类
泛型的下限:
- 格式:
类型名称 <? super 类 > 对象名称
- 意义:
只能接收该类型及其父类型
比如:现已知Object类,String 类,Number类,Integer类,其中Number是Integer的父类
public class Test {
public static void main(String[] args) {
/*
通配符高级使用----受限泛型:
上限: <? extends 类名> 只能接收该类类型或者其子类类型
下限: <? super 类名> 只能接收该类类型或者其父类类型
*/
// 关系:String继承Object,Integer继承Number,Number继承Objec
ArrayList<Object> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Integer> list3 = new ArrayList<>();
ArrayList<Number> list4 = new ArrayList<>();
method1(list1);
method1(list2);
method1(list3);
method1(list4);
//method2(list1);// 编译报错
//method2(list2);// 编译报错
method2(list3);
method2(list4);
method3(list1);
//method3(list2);// 编译报错
method3(list3);
method3(list4);
}
// 定义一个方法,只可以接收以上list3和list4集合
public static void method2(ArrayList<? extends Number> list){
}
// 定义一个方法,只可以接收以上list3和list4,list1集合
public static void method3(ArrayList<? super Integer> list){
}
// 定义一个方法,可以接收以上4个集合
public static void method1(ArrayList<?> list){
}
// 定义一个方法,可以接收以上4个集合
public static void method(ArrayList list){
}
}