一、集合概述
1、数组的特点
- 数组的大小是固定的,一旦创建后,数组的大小是无法改变的。
- 数组只能存储相同类型的数据。
- 数组查询效率高(有索引,元素内存连续分配),增删效率低(不断的扩容)。
2、数组和集合的区别
相同点:
- 都是容器,都可以存储多个数据。
- 都可以存储引用类型的数据。
区别:
- 数组长度不可变。
- 集合长度可变。
- 数组既可以存储基本类型数据,也可以存储引用类型数据。
- 集合只能存储引用类型数据,如果要存储基本类型,需要存储对应的包装类。
3、为什么要用集合?
数组的缺点: 不灵活,容量需要事先定义好,不能随着需求的变化而扩容。
但是我们的开发又不可能离开数组,所以最初就只能依靠一些数据结构来实现动态的数组处理,其中最为重要的两个数据结构:链表、数组,但是面对这些数据结构的实现又不得不面对如下的问题?
-
数据结构的代码实现困难,对于一般的开发者是无 法进行使用的。
-
对于链表或二叉树当进行更新处理的时候维护是非常麻烦的。
-
对于链表或二叉树还需要尽可能保证其操作的性能。
正是因为这样的原因,所以从JDK1.2开始Java引入了集合的概念,主要就是对常见的数据结构进行完整的实现包装,并且提供了一些列接口和实现类来帮助用户减少数据结构所带来的开发困难。
最初的集合实现由于Java本身的技术所限,所以对数据的控制并不严格,全部采用了Object类型进行数据的接收;在JDK1.5之后由于泛型技术的推广,集合框架也得到了良好的改进,可以直接利用泛型来保存相同类型的数据;随着数据量的不断增加,从JDK1.8开始集合框架中的实现算法也得到了良好的性能提升。

二、Collection集合
java.util.Collection<E>
是单列集合操作的最大的父接口,在该接口中定义了单列集合的所有操作。
Collection接口实现类的特点:
- 有些Collection的子接口/实现类,可以存放重复的元素,有些不可以。
- 有些Collection的子接口/实现类,有些是有序的(如 List),有些不是有序的(如 Set)。
- Collection接口没有直接的实现子类,是用过它的子接口Set和List来实现的。
1、Collection集合常用方法
方法名称 | 功能 |
---|---|
boolean add(E e) | 添加单个元素 |
boolean addAll(Collection coll) | 把coll集合中的所有元素复制一份,并添加到当前集合中 |
void clear() | 清空集合中的所有元素 |
boolean contains(Object o) | 判断当前集合中是否包含指定的数据 (需要equals方法支持) |
boolean isEmpty() | 判断当前合是否为空 |
boolean remove(Object o) | 删除(有相同元素,只能删除一个)(需要equals方法支持) |
int size() | 获取集合中元素的个数 |
Object[] toArray() | 将集合变成Object数组返回 |
Iterator<E> iterator() | 返回此集合中元素的迭代器 |
在进行集合操作的时候有两个方法最为常用:【添加数据】add()、【输出数据】iterator(),在JDK1.5版本之前Collection只是一个独立的接口,但是从JDK1.5之后提供了Iterable父接口,并且在JDK1.8之后 Iterable 接口也得到一些扩充。
但是往往我们玩的都是Collection的两个子接口: List(有序有索引可重复)、Set(无序不可以重复)接口。
使用场景的总结:
1、如果希望元素可以重复,又有索引,索引查询要快?
- 用 ArrayList集合,基于数组的。(用的最多,例如获取用户数据等等)
2、如果希望元素可以重复,又有索引,增删首尾操作快?
- 用 LinkedList集合,基于链表的。(栈、队列、排队系统)
3、如果希望增删改查都快,但是元素不重复、无序、无索引。
- 用 HashSet集合,基于哈希表的。
4、如果希望增删改查都快,但是元素不重复、有序、无索引。
- 用 LinkedHashSet集合,基于哈希表和双链表。
5、如果要对对象进行排序。
- 用 TreeSet集合,基于红黑树。后续也可以用List集合实现排序(sort方法)。
2、Collection集合的遍历元素
(1) 使用Iterator(迭代器)遍历
我们知道Collection继承了Iterable接口,而在Iterable接口中定义了一个iterator()抽象方法,用于返回一个Iterator对象即迭代器对象,来遍历集合中所有元素。
而在Collection接口中重写了Iterable接口的iterator()方法,所以Collection的 子接口/实现类 都会有这个iterator()方法。
- Iterator对象称为迭代器,主要用于遍历 Collection 集合中的元素。(因为它不能使用for+get(索引)方式取元素)
- 所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个Iterator接口的实现类对象,即迭代器对象。
- Iterator仅用于遍历集合,Iterator本身并不存放对象。
Iterator接口中的方法:
方法 | 功能 |
---|---|
boolean hasNext() | 如果仍有元素可以迭代,则返回 true 。 |
E next() | 返回迭代的下一个元素。 |
default void remove() | 使用迭代器删除集合中的元素,它会自动更新迭代器,并且更新集合。 |
迭代器的执行原理:
迭代器源代码分析:
注意:
-
在调用next()方法之前必须先调用hasNext()方法来检测下一个元素是否存在。若不调用且下一条记录无效时(也就是已经遍历完所有元素),再调用next()会抛出
NoSuchElementException
异常。 -
当while循环结束后,iterator迭代器会指向最后一个元素,如果希望再次遍历集合,需要重新获取新的迭代器对象。
-
如果在迭代器中添加删除指定元素,则会报
ConcurrentModificationException
并发修改异常。- 参考:https://blog.csdn.net/yztfst/article/details/97834440
-
如果要在迭代器中删除指定元素,需要调用iterator的remove()方法,他会自动更新迭代器,并且更新集合。
(2) 使用增强for循环遍历
增强for循环,JDK1.5新特性
增强for循环可以代替iterator迭代器,它只能用于遍历数组或集合。
语法格式:
for(元素类型 变量名 :集合或数组名){
sout(变量名)
}
如果遍历数组:foreach底层源码是普通for循环。
如果遍历集合:foreach底层源码是iterator迭代器(简化版的迭代器),只能对集合进行遍历操作。
扩展:使用指定编码编译 javac -encoding utf-8 xx.java
三、常见的数据结构
数据接口有:数组、队列、栈、链表、树、散列、堆、图。
1、栈
特点:先进后出、后进先出、入栈(压栈)、出栈(弹栈)。
2、队列
特点: 先进先出、后进后出(例如排队做核酸)
3、数组
特点:查询快(有索引、元素内存连续分配)、增删慢(不断扩容)。
4、链表
特点:查询慢(需要遍历),增删快(不需要创建新的链表,只需修改链表中节点保存的地址)。
单项链表:
双向链表:
链表查询慢的原因:
- 它需要遍历链表中的节点,然后使用算法判断是从前向后查,还是从后向前查。
- 从前向后查:要查询节点的编号<节点数/2 。
- 从后向前查:要查询节点的编号>=节点数/2。
5、树
树
- 结点:树中的数据元素都称为结点。例如 A、B、C、D、E等等
- 根:最上面的结点称之为根,一颗树只有一个根且由根发展而来,从另外一个角度来说,每个结点都可以认为是其子树的根。
- 父亲:结点的上层结点,如图中,结点K的父亲是E、结点L的父亲是G。
- 结点的度:结点所拥有的子树的个数称之为结点的度,如结点B的度为3
- 树叶:度为0的结点,也叫作终端结点,图中D、K、F、L、H、I、J都是树叶。
- 分支结点:度不为0的结点,也叫作非终端结点或内部结点,图中根、A、B、C、E、G都是分支结点
- 结点的层次:从根节点到树中某结点所经路径上的分支树称为该结点的层次,根节点的层次规定为1,其余结点的层次等于其父亲结点的层次+1。
二叉树
二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。(左边小、右边大)
查找二叉树
二叉树的一个重要应用是在它们查找中的使用,假设树中的每个结点存储一项数据,使得二叉树成为二叉查找树的性质是:对于树中的每个结点X,它的左子树中所有项的值小于X,而它的右子树中所有项的值大于X,这意味着该树所有的元素可以用某种一致的方式排序。
平衡二叉树
在生成二叉树/二叉查找树的时候是非常容易失衡的,造成的最坏的情况就是一边倒(只有左子树/右子树),这样将会导致树的检索效率大大降低,所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,比如:AVL树–每个结点的左子树和右子树深度最多差1。
红黑树
红黑树顾名思义就是结点是红色或者黑色的平衡二叉树,它通过颜色的约束来维持着二叉树的平衡。
对于一颗有效的红黑树而言我们必须增加如下规则:
- 每个结点都只能是红色或者黑色;
- 根节点是黑色;
- 每片叶子都是黑色的;
- 如果一个结点是红色的,则它的两个子节点都是黑色的,也就是说在一条路径上不能出现相邻的两个红色结点;
- 从任意一个结点到其每个叶子的所有路径都包含着相同数目的黑色结点。
这些约束强制了红黑树的关键性质:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果就是这棵树大致上是平衡的,因为插入、删除和查找某个值得最坏情况时间都要求与树的高度成比例,这个高度理论上限允许红黑树只在最坏情况下都是高效的。
四、泛型
1、泛型概述
集合它可以存放任意对象,当把对象存储到集合后,他们都会被提升成Object类型。然后我们再取出每一个对象并且进行相应操作时,必须采用强制类型转换。
public class Demo01Generic {
public static void main(String[] args) {
// 创建一个ArrayList集合对象,指定存储数据的类型为String
ArrayList<String> list = new ArrayList<>();
list.add("aa");
list.add("bbb");
list.add("cccc");
// 将运行时异常,提前到了编译时期,降低了程序员的工作量
//list.add(1000); //只能存String类型数据
// 使用增强for进行遍历
for (String str : list) {
System.out.println(str + "的长度: " + str.length());
}
System.out.println("===================");
// 创建集合,不指定存储数据的类型
// 默认按照Object类型处理
ArrayList list2 = new ArrayList();
list2.add("aa");
list2.add("bbb");
list2.add("cccc");
// 可以存
// 但是取出来进行强制类型转换,报出类型转换异常
list2.add(2022);
// 使用增强for进行遍历
for (Object obj : list2) {
// 因为创建ArrayList集合对象时,并没有指定存储数据的类型(泛型),
// 所以内部存储的所有内容均被当做Object类型处理
// 必须做强制类型转换(向下转型),存在安全隐患:类型转换异常 ClassCastException
String str = (String) obj;
System.out.println(obj + "的长度: " + str.length());
}
}
}
为什么会报错ClassCastException?因为上述的ArrayList集合只能存储同一类型对象(例如list2存储的都是字符串对象),当取出String类型数据时需要强转,即Object强转成String,又因为元素2022它强转后是Integer而不是String类型,所以把Integer类型的数据赋值给String类型后就会报ClassCastException类型转换异常。解决方案:使用泛型来约束集合存储指定类型数据。
什么是泛型?
泛型是程序设计语言的一种风格或范式。
泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型(相当于占位符,可以被预先使用),在实例化时作为参数指明这些类型(实现代码的模板化,把数据类型当做参数传递)。其目的是加强类型安全以及减少类型转换的次数。
泛型是 JDK1.5之后增加的,允许在定义类和接口以及方法时使用类型参数(Type Parameter)。泛型它可以帮助我们建立类型安全的集合。提高了代码复用性和安全性。
使用泛型的好处?
- 可以避免强制类型转换的麻烦。
- 将运行时异常,提前到了编译时期,降低了程序员的工作量。
- 一旦指定泛型,数据类型将被统一。
- 实现代码的模板化,把数据类型当做参数传递。
2、泛型的分类
泛型类、泛型接口、泛型方法。
(1) 泛型类
如何定义泛型类:在类的声明处添加泛型变量即可。
泛型变量一般用大写字母表示 , 如 T(Type),E(Element),K(Key),V(Value)
。
如果一次要声明多个泛型变量,中间用逗号,
分割即可。例如<T,E,K,V>
。
格式如下:
public class 类名<泛型变量>{
}
//例如
public class MyClass<T> {
}
示例:泛型类的使用
// 定义一个泛型类
public class MyClass<T> {
// 定义成员变量
private T t;
// 无参构造器
public MyClass() {
}
// 有参构造器
public MyClass(T t) {
this.t = t;
}
// set/get方法
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
// toString方法
@Override
public String toString() {
return "MyClass{" +
"t=" + t +
'}';
}
}
测试类:
public class Demo02Generic {
public static void main(String[] args) {
// 使用无参构造器创建对象,并指定泛型
MyClass<String> mc = new MyClass<>();
// 使用set方法为成员变量赋值
mc.setT("helloworld");
System.out.println(mc); //MyClass{t=helloworld}
// 使用get方法取值
String str = mc.getT(); //因为创建对象的时候传了泛型,所以返回值类型就是Stirng类型
System.out.println(str); //helloworld
// 使用有参构造器创建对象
MyClass<Integer> mc02 = new MyClass<>(100);//发生自动装箱操作
//错误示范: 左侧<>中指定了Integer类型,有参构造右侧只能传递Integer数据,不能传递字符串
//MyClass03<Integer> mc02 = new MyClass03<>("100");
//调用toString方法获取数据
String s2 = mc02.toString();
System.out.println(s2); //MyClass{t=100}
}
}
(2) 泛型方法
泛型方法可以是普通方法、静态方法和构造器方法。
泛型方法定义格式:
修饰符 <泛型变量> 返回值类型 方法名(参数类型 参数列表){
}
//例如Collections的两个泛型方法
public <T> T[] toArray(T[] a){
return s.toArray(a);
}
public static <T> boolean addAll(Collection<? super T> c, T... elements) {
boolean result = false;
for (T element : elements)
result |= c.add(element);
return result;
}
示例:泛型方法的使用
public class MyClass<T> {
/*
这种定义方法不叫泛型方法(因为它使用类上定义的泛型)
*/
public void method(T t){
System.out.println(t);
}
//定义非静态泛型方法
//泛型方法: 该泛型只属于当前方法使用
public <E> void show(E e) {
System.out.println(e);
}
/*
错误示范:
静态方法必须使用类名直接调用,和对象无关
但是类上的泛型,必须创建对象后才能确定具体的类型
然而静态方法和对象无关,调用时根本没有对象,就没有泛型
总结:
静态方法,不能使用类上定义的泛型,只能使用方法中的泛型
*/
/*public static void fun(T t){
System.out.println(t);
}*/
//定义静态泛型方法
public static <K> void test(K k) {
System.out.println(k);
}
}
测试类:
public class Demo01GenericMethod {
public static void main(String[] args) {
MyClass<String> mc01 = new MyClass<>();
mc01.method("hello");
/*
错误示范:
method方法使用类上的泛型已经被确定为了String,
就不能传递String以外的类型
*/
//mc01.method(100);
/*
正确写法:
show方法上有自己的泛型,
根据调用方法传递的参数的类型,来确定方法上泛型的类型
*/
mc01.show("World");
mc01.show(100);
mc01.show(new Student("zs", 18));
/*
正确写法:
test方法上有自己的泛型,
根据调用方法传递的参数的类型,来确定方法上泛型的类型
*/
MyClass.test("Java");
MyClass.test(200);
MyClass.test(new Student("ls",38));
}
}
(3) 泛型接口
泛型接口定义格式如下:
public interface 接口名称<泛型变量> {
}
//例如
public interface Iterable<T> {}
public interface Collection<E> extends Iterable<E> {}
public interface List<E> extends Collection<E> {}
public interface Set<E> extends Collection<E> {}
public interface Map<K,V> {}
示例:泛型接口
public interface MyInter<T> {
// 抽象方法
/*public abstract */void method(T t);
}
实现类:MyInterImplA
/*
已经确定接口要传的类型 String
*/
public class MyInterImplA implements MyInter<String> {
@Override
public void method(String str) {
System.out.println(str);
}
}
实现类:MyInterImplB
/*
不确定接口要传的类型
把实现类定义成泛型类,在实现接口时,就可以使用类上定义的泛型啦QAQ
*/
public class MyInterImplB<T> implements MyInter<T> {
@Override
public void method(T t) {
System.out.println(t);
}
}
测试类:
public class MyTest {
public static void main(String[] args) {
MyInterImplA mia = new MyInterImplA();
mia.method("Hello");
MyInterImplB<String> mib = new MyInterImplB<>(); //指定泛型
mib.method("World");
MyInterImplB<Student> mib2 = new MyInterImplB<>();//指定泛型
mib2.method(new Student("zs",18));
}
}
3、泛型通配符
泛型通配符: ? 可以理解成占位符,用来匹配泛型的,但是不能使用?定义泛型。
主要应用场景: 定义参数/变量时,不能确定变量的具体类型时,使用?代替。
示例1:
public class Demo01TongPeiFu {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("AAA");
list.add("BBB");
list.add("CCC");
Set<Integer> set = new HashSet<>();
set.add(111);
set.add(222);
set.add(333);
//调用方法
print(list);
print(set);
System.out.println("-------------");
//调用方法
print2(list);
print2(set);
}
/**
* 定义一个方法,完成以上两个集合的遍历
* 泛型通配符: ? 就是一个占位符, 用来匹配泛型的,但是不能使用?定义泛型。
* @param coll
*/
public static void print2(Collection<?> coll) {
for (Object o : coll) {
System.out.println(o);
}
}
/*
定义一个方法,完成以上两个集合的遍历
目前: 把print方法定义成了泛型方法
方法参数:
使用Collection接口定义变量,Collection接口在定义时是有泛型的,
使用Collection接口定义变量,需要指定泛型
泛型是不存在的多态的
此处:
print2方法是一个泛型方法
*/
public static <T> void print(Collection<T> coll) {
for (T t : coll) {
System.out.println(t);
}
}
}
示例2:
public class Demo02TongPeiFuNotice {
public static void main(String[] args) {
List<Object> list1 = new ArrayList<>();//右侧<>中省略不写,就是Object
List<Object> list2 = new ArrayList<Object>();//右侧<>中写Object也是可以的
//List<Object> list3 = new ArrayList<String>();//错误: 左右两边<>中的数据类型必须一致,泛型不存在多态
//List<Object> list4 = new ArrayList<Integer>();//错误: 左右两边<>中的数据类型必须一致,泛型不存在多态
//List<Object> list5 = new ArrayList<Student>();//错误: 左右两边<>中的数据类型必须一致,泛型不存在多态
List list6 = new ArrayList(); //不加泛型默认是Object类型
//?通配符: 用来匹配泛型的,不能用来定义泛型
//主要的应用场景: 定义参数/变量时,不能确定变量的具体类型时,使用?代替
//?: 代表任意一种引用类型
List<?> list;
list = new ArrayList<>();//<>不写数据类型代表Object
list = new ArrayList<String>(); //String
list = new ArrayList<Integer>(); //Integer
list = new ArrayList<Student>(); //Student
/*
注意事项:
1.泛型是不存在多态的,左侧<>中写的类型必须和右侧<>中的类型保持一致(可以省略右侧<>中的内容)
2.使用泛型通配符,定义变量:
List<?> list 可以接收哪些对象?
只要是List接口实现类的任意泛型对象就可以(创建对象时,只要在<>中写上一种引用类型就行)
3.List<?> list: 理解为它是各种泛型List集合对象的父类
*/
}
}
4、泛型上限和下限
泛型通配符的限制
(1) 泛型的上限
一个父类的子类可以有任意多个,那如何表示出一个父类的任意子类呢?(找儿子)
泛型的上限:
// ?: 代表的是任意一种引用类型
? extends Person: 表示Person类型或者Person类型的任意子类型
? extends E: 表示E类型或者E类型的任意子类型
示例:泛型上限的使用
//Person类
public class Person {
private String name;
private int age;
//生成空参,满参构造,set和get方法
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//Worker类 工人
public class Worker extends Person {
//根据父类生成空参,满参构造
public Worker() {
}
public Worker(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "Worker{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
}
}
//Teacher类
public class Teacher extends Worker {
//根据父类生成空参,满参构造
public Teacher() {
}
public Teacher(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "Teacher{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
}
}
//JavaTeacher类
public class JavaTeacher extends Teacher {
public JavaTeacher() {
}
//根据父类生成空参,满参构造
public JavaTeacher(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "JavaTeacher{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
}
}
测试类:
@SuppressWarnings("all") //抑制警告
public class Demo01GenericShangXian {
public static void main(String[] args) {
ArrayList<Person> list1 = new ArrayList<>();
list1.add(new Person("zs", 18));
list1.add(new Person("ls", 28));
list1.add(new Person("ww", 38));
ArrayList<Worker> list2 = new ArrayList<>();
list2.add(new Worker("zs01", 18));
list2.add(new Worker("ls01", 28));
list2.add(new Worker("ww01", 38));
ArrayList<Teacher> list3 = new ArrayList<>();
list3.add(new Teacher("zs02", 18));
list3.add(new Teacher("ls02", 28));
list3.add(new Teacher("ww02", 38));
ArrayList<String> list4 = new ArrayList<>();
list4.add("aaa");
list4.add("bbb");
ArrayList<Integer> list5 = new ArrayList<>();
list5.add(100);
list5.add(200);
print(list1);
print(list2);
print(list3);
// print(list4); //错误:String不是Person的子类
// print(list5); //错误:Integer不是Person的子类
}
/**
* 定义一个方法,只能完成以下3个集合的遍历
* ArrayList<Person>、ArrayList<Worker>、ArrayList<Teacher>
* Worker是Person的子类,Teacher也是Person的子类
* ? extends Person: 代表Person类型或者Person类型的任意子类类型
* @param list
*/
public static void print(ArrayList<? extends Person> list) {
for (Person person : list) {
System.out.println(person);
}
System.out.println("---------------");
}
}
(2) 泛型的下限
一个子类的父类可以有任意多个,如何表示一个子类的任意父类类型呢?(找爹)
泛型的上限:
// ?: 代表的是任意一种引用类型
? super JavaTeacher: 代表JavaTeacher类型或者JavaTeacher类型的任意父类类型
? super T: 代表T类型或者T类型的任意父类类型
示例:泛型下限的使用
//Person类
public class Person {
private String name;
private int age;
//生成空参,满参构造,set和get方法
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//Worker类 工人
public class Worker extends Person {
//根据父类生成空参,满参构造
public Worker() {
}
public Worker(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "Worker{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
}
}
//Teacher类
public class Teacher extends Worker {
//根据父类生成空参,满参构造
public Teacher() {
}
public Teacher(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "Teacher{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
}
}
//JavaTeacher类
public class JavaTeacher extends Teacher {
public JavaTeacher() {
}
//根据父类生成空参,满参构造
public JavaTeacher(String name, int age) {
super(name, age);
}
@Override
public String toString() {
return "JavaTeacher{" + "name='" + getName() + '\'' + ", age=" + getAge() + '}';
}
}
测试类:
public class Demo02GenericXiaXian {
public static void main(String[] args) {
ArrayList<Person> list1 = new ArrayList<>();
list1.add(new Person("zs", 18));
list1.add(new Person("ls", 28));
list1.add(new Person("ww", 38));
ArrayList<Worker> list2 = new ArrayList<>();
list2.add(new Worker("zs01", 18));
list2.add(new Worker("ls01", 28));
list2.add(new Worker("ww01", 38));
ArrayList<Teacher> list3 = new ArrayList<>();
list3.add(new Teacher("zs02", 18));
list3.add(new Teacher("ls02", 28));
list3.add(new Teacher("ww02", 38));
ArrayList<String> list4 = new ArrayList<>();
list4.add("aaa");
list4.add("bbb");
ArrayList<Integer> list5 = new ArrayList<>();
list5.add(100);
list5.add(200);
ArrayList<JavaTeacher> list6 = new ArrayList<>();
list3.add(new JavaTeacher("zs02", 18));
list3.add(new JavaTeacher("ls02", 28));
list3.add(new JavaTeacher("ww02", 38));
print(list1);
print(list2);
print(list3);
// print(list4); //错误:String不是Teacher的父类
// print(list5); //错误:Integer不是Teacher的父类
// print(list6); //错误:JavaTeacher不是Teacher的父类
}
/**
* 使用泛型下限变量一下三个集合定义一个方法
* ArrayList<Person> list1、ArrayList<Worker> list2 、ArrayList<Teacher> list3
*
* @param list
*/
public static void print(ArrayList<? super Teacher> list) {
for (Object o : list) {
System.out.println(o);
}
System.out.println("---------------");
}
}
五、List集合
ArrayList
LinkedList
六、Set集合
HashSet
LinkedHashSet
TreepSet
七、Map集合
java.util.Map<K,V>
集合是双列集合的根接口,内部定义的方法,子接口/实现类都有。