Java集合框架
什么是集合
- 概念:对象的容器,定义了对多个对象进行操作的常用方法,和数组类似。可以实现数组的功能。
- 和数组的区别:
- 数组长度固定,集合长度不固定。
- 数组可以存储基本类型和引用类型,集合只能存储引用类型。如果要存储基本类型,需要用到包装类装箱。
- 位置:java.util.*
Collection体系集合

Collection父接口
- 特点:代表一组任意类型的对象,无序、无下标(不能用普通for循环)、不能重复。
- 方法:
- boolean add(Object obj) //添加一个对象。
- boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
- void clear() //清空此集合中的所有对象。
- boolean contains(Object o) //检查此集合中是否包含o对象。
- boolean equals(Object o) //比较此集合是否与指定对象相等。
- boolean isEmpty() //判断此集合是否为空。
- boolean remove(Object o) //在此集合中移除o对象。
- int size() //返回此集合中的元素个数。
- Object[] toArray() //将此集合转换成数组。


- Collection接口的使用:基本方法
package collections;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* Collection接口的使用
* (1)添加元素
* (2)删除元素
* (3)遍历元素
* (4)判断
*/
public class Demo01 {
public static void main(String[] args) {
// 创建集合
Collection collection = new ArrayList();
// 1.添加元素
collection.add("苹果");
collection.add("西瓜");
collection.add("榴莲");
System.out.println("元素个数:" + collection.size());
System.out.println(collection);
// 2.删除元素
collection.remove("榴莲");
System.out.println("删除之后元素个数:" + collection.size());
System.out.println("========榴莲已被删除========");
// 3.清空元素
// collection.clear();
// 4.遍历元素【重点】
// 4.1 方法一:增强for循环,没有下标
for (Object object :
collection) {
System.out.println(object);
}
System.out.println("========没有榴莲了哦========");
// 4.2 方法二:使用迭代器(专门用来遍历集合的一种方式)
//hasNext(); 判断有没有下一个元素
//next(); 获取下一个元素
//remove(); 删除当前元素
Iterator it = collection.iterator();
// 迭代器迭代过程中不允许使用 Collection 的删除方法。
// 不然会报错 并发修改异常,但是可以使用迭代器自身的删除方法
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
// collection.remove(s); 报错,因为迭代器正在使用这个元素,你给删了,合适吗?
// it.remove(); 但是用迭代器自己的方法是可以删的!
}
// 5.判断
System.out.println(collection.contains("西瓜"));
System.out.println(collection.isEmpty());
}
}
迭代器Iterator的三个方法:

迭代器工作时,使用collections修改元素,会报错:
Iterator it = collection.iterator();
// 迭代器迭代过程中不允许使用 Collection 的删除方法。
// 不然会报错 并发修改异常,但是可以使用迭代器自身的删除方法
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
collection.add("猕猴桃"); // 报错,迭代器不允许并发修改
// 因为迭代器正在使用这个元素,你给删了,合适吗?
// it.remove(); //但是用迭代器自己的方法是可以的!
}

- Collections接口的使用:保存学生信息
学生类:
package collections.demo02;
/**
* 学生类
*/
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package collections.demo02;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 保存学生信息
*/
public class Demo02 {
public static void main(String[] args) {
// 新建 Collection 对象
Collection collection = new ArrayList();
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 18);
Student s3 = new Student("王五", 22);
// 1.添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
collection.add(s3); // 可以添加重复的,ArrayList
System.out.println("元素个数:" + collection.size());
System.out.println(collection.toString());
// 2.删除
collection.remove(s1);
// collection.remove(new Student("王五", 22)); // 这个对象和以前的对象是不一样的
// 3.清空
// collection.clear(); // 虽然把集合中的元素清空了,但是这三个对象还是存在的
System.out.println("删除之后:" + collection.size());
// 4。遍历
// 4.1 增强for循环
for (Object object :
collection) {
System.out.println(object);
}
System.out.println("==========================================");
// 4.2 迭代器: hasNext(); next(); remove()
// 迭代过程中不能使用collection的删除方法
Iterator it = collection.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.toString());
}
// 5.判断
System.out.println(collection.contains(s2));
System.out.println(collection.isEmpty());
}
}
结果:
元素个数:4
[Student{name='张三', age=20}, Student{name='李四', age=18}, Student{name='王五', age=22}, Student{name='王五', age=22}]
删除之后:3
Student{name='李四', age=18}
Student{name='王五', age=22}
Student{name='王五', age=22}
==========================================
Student{name='李四', age=18}
Student{name='王五', age=22}
Student{name='王五', age=22}
true
false
Collection子接口
- List 接口
- Set 接口
List集合
List子接口
-
特点:有序(添加元素和获取元素、遍历元素顺序是一致的)、有下标(可以用for循环)、元素可以重复。
-
方法:
-
包含Collection的方法。
-
void add(int index,Object o) // 在index位置插入对象o。
-
boolean addAll(int index,Collection c) // 将一个集合中的元素添加到此集合中的index位置。
-
Object get(int index) // 返回集合中指定位置的元素。
-
List subList(int fromIndex,int toIndex) // 返回fromIndex和toIndex之间的集合元素。
-
List子接口的使用
List集合使用(1)
package collections.list;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/**
* List子接口的使用
*/
public class Demo01 {
public static void main(String[] args) {
// 1.先创建集合对象
List list = new ArrayList<>();
// 2.添加元素
list.add("小米");
list.add("苹果");
list.add("三星");
list.add(0, "华为"); // 0的意思是在第一个位置添加
System.out.println("元素个数:" + list.size());
System.out.println(list.toString());
// 3. 删除元素
list.remove("苹果");
list.remove(2);
System.out.println("删除之后:" + list.size());
System.out.println(list.toString());
System.out.println("==========================================");
// 4.遍历
// 4.1普通for
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("==========================================");
// 4.2增强for
for (Object object :
list) {
System.out.println(object);
}
System.out.println("==========================================");
// 4.3迭代器
Iterator it = list.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println("==========================================");
// 4.4【列表迭代器】,可以向前或向后遍历,还可以添加、删除、修改替换原宿,还可以获得下标
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()) { // 从前往后遍历
System.out.println(listIterator.nextIndex() + ":" + listIterator.next());
}
System.out.println("==========================================");
while(listIterator.hasPrevious()) { // 从后往前
System.out.println(listIterator.previousIndex() + ":" + listIterator.previous());
}
System.out.println("==========================================");
// 5.判断
System.out.println(list.contains("苹果"));
System.out.println(list.isEmpty());
System.out.println("==========================================");
// 6.获取位置
System.out.println(list.indexOf("华为"));
}
}
结果:
元素个数:4
[华为, 小米, 苹果, 三星]
删除之后:2
[华为, 小米]
==========================================
华为
小米
==========================================
华为
小米
==========================================
华为
小米
==========================================
0:华为
1:小米
==========================================
1:小米
0:华为
==========================================
false
false
==========================================
0
List集合使用(2)
package collections.list;
import java.util.ArrayList;
import java.util.List;
/**
* List子接口的使用
*/
public class Demo02 {
public static void main(String[] args) {
// 创建集合
List list = new ArrayList();
// 1.添加数字数组(jdk1.5之后自动装箱,这里20不是基本类型int,是包装类Integer)
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.add(60);
list.add(70);
System.out.println("元素个数:" + list.size());
System.out.println(list);
// 2.删除
// list.remove(20); // 这样删除元素会报错,数组下标最大为4
// list.remove(0); // 可以通过下标删除对应的值
// list.remove((Object) 20); 可以这样删
// list.remove(new Integer(70)); 也可这样删
System.out.println("删除元素:" + list.size());
// 3.补充方法:sublist:返回子集合,含头不含尾
List subList = list.subList(1, 3);
System.out.println(subList);
}
}
结果:
元素个数:6
[20, 30, 40, 50, 60, 70]
删除元素:6
[30, 40]
List实现类
- ArrayList(数组列表集合)【重点】:
- 数组结构实现(底层是数组),查询快(数组空间连续)、增删慢;
- JDK1.2加入,运行效率快、线程不安全。
- 默认初始容量:10
- Vector(向量集合):现在用的不多了,和ArrayList比较像
- 数组结构实现,查询快、增删慢;
- JDK1.0加入,运行效率慢、但是线程安全。
- LinkedList(链表集合):
- 链表结构实现,增删快、查询慢。(双向链表,前一个节点指向后一个节点)
ArrayList使用
在Student学生类中重写了equals方法
package collections.demo02;
/**
* 学生类
*/
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) {
// 1.判断是不是同一个对象
if (this == obj) {
return true;
}
// 2.判断是否为空
if (obj == null) {
return false;
}
// 3.判断是否是Student类型
if (obj instanceof Student) {
Student s = (Student) obj;
// 4.比较属性
if (this.name.equals(s.getName()) && this.age == s.age) {
return true;
}
}
// 5.不满足条件返回false
return false;
}
}
package collections.list;
import collections.demo02.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
/**
* ArrayList的使用
*/
public class Demo03 {
public static void main(String[] args) {
// 创建集合
ArrayList arrayList = new ArrayList();
// 1.添加元素
Student s1 = new Student("liu", 20);
Student s2 = new Student("zhang", 21);
Student s3 = new Student("tang", 19);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:" + arrayList.size());
System.out.println(arrayList);
System.out.println("===========删除元素============");
// 2.删除元素
// arrayList.remove(0); // 通过下标删除
// arrayList.remove(s1);
arrayList.remove(new Student("liu", 20)); //调用equals(this==obj),若要实现这个删除,就重写equals方法
System.out.println("删除之后:" + arrayList.size());
System.out.println(arrayList);
// 3.遍历元素【重点】
// 3.1使用迭代器
System.out.println("===========使用迭代器============");
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()) {
Student student = (Student) iterator.next();
System.out.println(student.toString());
}
// 3.2使用列表迭代器
System.out.println("===========使用列表迭代器(顺序)============");
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()) {
Student student = (Student) listIterator.next();
System.out.println(student.toString());
}
System.out.println("===========使用列表迭代器(逆序)============");
while (listIterator.hasPrevious()) {
Student student = (Student) listIterator.previous();
System.out.println(student.toString());
}
// 4.判断
System.out.println("===========判断============");
// 重写了equals方法,此时会找到new的对象
System.out.println(arrayList.contains(new Student("tang", 19)));
System.out.println(arrayList.isEmpty());
// 5.查找
System.out.println("===========查找============");
System.out.println(arrayList.indexOf(new Student("tang", 19)));
}
}
结果:
元素个数:3
[Student{name='liu', age=20}, Student{name='zhang', age=21}, Student{name='tang', age=19}]
===========删除元素============
删除之后:2
[Student{name='zhang', age=21}, Student{name='tang', age=19}]
===========使用迭代器============
Student{name='zhang', age=21}
Student{name='tang', age=19}
===========使用列表迭代器(顺序)============
Student{name='zhang', age=21}
Student{name='tang', age=19}
===========使用列表迭代器(逆序)============
Student{name='tang', age=19}
Student{name='zhang', age=21}
===========判断============
true
false
===========查找============
1
ArrayList源码分析
-
默认容量大小:
- DEFAULT_CAPACITY = 10
- 注意:如果没有向集合中添加任何元素时,数组的容量为0,任意添加一个元素,容量变为10
-
存放元素的数组:
- elementData
-
实际元素个数
- size
-
add()方法
-
待补充
-
扩容:每次都是原来的1.5倍
-
Vector使用
package collections.vector;
import java.util.Enumeration;
import java.util.Vector;
/**
* Vector集合的使用
*/
public class Demo01 {
public static void main(String[] args) {
// 创建集合
Vector vector = new Vector();
// 1.添加元素
vector.add("草莓");
vector.add("苹果");
vector.add("西瓜");
System.out.println("元素个数:" + vector.size());
System.out.println("=========删除=========");
// 2.删除
// vector.remove(0);
vector.remove("西瓜");
// vector.clear();
System.out.println(vector);
// 3.遍历
// 使用枚举器
System.out.println("=========枚举器遍历=========");
Enumeration elements = vector.elements();
while(elements.hasMoreElements()) {
String o = (String) elements.nextElement();
System.out.println(o);
}
// 4.判断
System.out.println("=========判断=========");
System.out.println(vector.contains("西瓜"));
System.out.println(vector.isEmpty());
// 5.其他方法
System.out.println("=========获取第一个元素=========");
System.out.println(vector.firstElement());
System.out.println("=========获取最后一个元素=========");
System.out.println(vector.lastElement());
System.out.println("=========获取下标为0的元素=========");
System.out.println(vector.get(0));
System.out.println("=========获取下标为1的元素=========");
System.out.println(vector.elementAt(1));
}
}
结果:
元素个数:3
=========删除=========
[草莓, 苹果]
=========枚举器遍历=========
草莓
苹果
=========判断=========
false
false
=========获取第一个元素=========
草莓
=========获取最后一个元素=========
苹果
=========获取下标为0的元素=========
草莓
=========获取下标为1的元素=========
苹果
LinkedList使用
存储结构:双向链表
package collections.linkedlist;
import collections.demo02.Student;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
/**
* LinkedList的使用
* 双向链表
*/
public class Demo01 {
public static void main(String[] args) {
// 创建集合
LinkedList linkedList = new LinkedList();
// 1.添加元素
Student s1 = new Student("张三", 20);
Student s2 = new Student("李四", 18);
Student s3 = new Student("王五", 22);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:" + linkedList.size());
System.out.println(linkedList);
// 2.删除
System.out.println("=========删除=========");
// linkedList.remove(s1);
linkedList.remove(new Student("张三", 20));
System.out.println("删除之后:" + linkedList.size());
// linkedList.clear(); // 清空
// 3.遍历
// 3.1for遍历
System.out.println("=========for遍历=========");
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
// 3.2增强for
System.out.println("=========增强for遍历=========");
for (Object o : linkedList) {
System.out.println(o);
}
// 3.3迭代器
System.out.println("=========迭代器=========");
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()) {
Student s = (Student) iterator.next();
System.out.println(s);
}
// 3.4列表迭代器
System.out.println("=========列表迭代器=========");
ListIterator listIterator = linkedList.listIterator();
while (listIterator.hasNext()) {
Student s = (Student) listIterator.next();
System.out.println(s);
}
// 4.判断
System.out.println("=========判断=========");
System.out.println(linkedList.contains("张三"));
System.out.println(linkedList.isEmpty());
// 5.获取位置
System.out.println("=========获取位置=========");
System.out.println(linkedList.indexOf(s2));
}
}
结果:
元素个数:3
[Student{name='张三', age=20}, Student{name='李四', age=18}, Student{name='王五', age=22}]
=========删除=========
删除之后:2
=========for遍历=========
Student{name='李四', age=18}
Student{name='王五', age=22}
=========增强for遍历=========
Student{name='李四', age=18}
Student{name='王五', age=22}
=========迭代器=========
Student{name='李四', age=18}
Student{name='王五', age=22}
=========列表迭代器=========
Student{name='李四', age=18}
Student{name='王五', age=22}
=========判断=========
false
false
=========获取位置=========
0
LinkedList源码分析
-
size:集合大小
-
first:头节点
-
last:根节点
-
add()方法:
-
public boolean add(E e) { linkLast(e); return true; }
-
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
-
Node类
-
private static class Node<E> { E item; // 节点中的实际数据 Node<E> next; // 后一个节点 Node<E> prev; // 前一个节点 Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
-
ArrayList和LinkedList区别

- ArrayList:必须开辟连续空间,查询快,增删慢。
- LinkedList:无需开辟连续空间,查询慢,增删快。(删除的元素并没有被垃圾回收器回收,只是从集合中删除了)
泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法、
- 语法:
- <T,…> T称为类型占位符,表示一种引用类型。
- 好处:
- 提高代码的重用性:一个方法可以传递任何类型的数据。
- 防止类型转换异常,提高代码的安全性
泛型类
package collections.generic;
/**
* 泛型类
* 在类名的后面加<T...>,表示一种引用类型,可以写多个,中间用逗号隔开
*/
public class MyGeneric<T> {
// 使用泛型T
// 1.创建变量
// 可以创建变量,但是不能实例化,不能保证传过来的类型构造方法一定能用
// 不能保证一定有无参构造
T t;
// 2.泛型作为方法参数
public void show(T t) {
System.out.println(t);
}
// 3.泛型作为方法的返回值
public T getT() {
return t;
}
}
package collections.generic;
public class TestCeneric {
public static void main(String[] args) {
// 使用泛型类创建对象
//注意:1.泛型只能用引用类型 2.不同泛型类型对象之间不能相互赋值
MyGeneric<String> myGeneric = new MyGeneric<>(); // JDK1.7之后<>里可以不写
myGeneric.t = "hello";
myGeneric.show("大家好");
System.out.println(myGeneric.getT());
MyGeneric<Integer> myGeneric1 = new MyGeneric<>();
myGeneric1.t = 100;
myGeneric.show("200");
System.out.println(myGeneric1.getT());
}
}
结果:
大家好
hello
200
100
泛型接口
package collections.generic;
/**
* 泛型接口
* 语法 接口名<T>
* 注意:不能泛型静态常量
* @param <T>
*/
public interface MyInterface<T> {
String name = "张三";
// 泛型接口
T server(T t);
}
package collections.generic;
/**
* 接口实现类 方式一
* 创建实现类的时候就已经确定了泛型是什么(String)
*/
public class MyInterfaceImpl implements MyInterface<String> {
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
package collections.generic;
/**
* 接口实现类 方式二
* 现在还不确定泛型是什么,由 MyInterfaceImpl2 来决定
*/
public class MyInterfaceImpl2<T> implements MyInterface<T> {
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
package collections.generic;
public class TestGeneric2 {
public static void main(String[] args) {
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.server("12345");
MyInterfaceImpl2 impl2 = new MyInterfaceImpl2();
impl2.server(1000);
}
}
结果:
12345
1000
泛型方法
package collections.generic;
/**
* 泛型方法
* 语法:<T>放在方法返回值类型前面
*/
public class MyGenericMethod {
// 泛型方法
public <T> T show(T t) {
System.out.println("泛型方法" + t);
return t;
}
}
package collections.generic;
// 泛型方法的使用
public class TestGeneric3 {
public static void main(String[] args) {
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show("中国加油");
myGenericMethod.show(200);
myGenericMethod.show(3.14);
}
}
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能互相赋值,泛型不存在多态。
package collections.generic;
import collections.demo02.Student;
import java.util.ArrayList;
import java.util.Iterator;
public class Demo01 {
public static void main(String[] args) {
// 在创建集合对象时已经确定了对象类型为 String
ArrayList<String> arrayList = new ArrayList<>();
// arrayList.add(1234); 报错,只能添加字符串类型
arrayList.add("xxx");
for (String string : arrayList) {
System.out.println(string);
}
ArrayList<Student> arrayList1 = new ArrayList<>();
Student student1 = new Student("a",11);
Student student2 = new Student("b",12);
Student student3 = new Student("c",13);
arrayList1.add(student1);
arrayList1.add(student2);
arrayList1.add(student3);
Iterator<Student> iterator = arrayList1.iterator();
while (iterator.hasNext()) {
Student s = iterator.next();
System.out.println(s);
}
}
}
Set集合
Set子接口
- 特点:无序、无下标、元素不可重复。
- 方法:全部继承自Collection中的方法,一模一样,没有提供新的方法。
Set实现类
-
HashSet【重点】
- 基于HashCode实现元素不重复。
- 线程不安全。
- 当存入元素的哈希码相同时,会调用equals确认,若果结果为true,则拒绝后者存入。
-
LinkedHashSet:
- 跟HashSet一模一样,只是有序。
-
TreeSet:
- 基于排列顺序实现元素不重复。
- 存储结构为红黑树(二叉树的一种,平衡二叉树)
- 实现了SortedSet接口,对集合元素自动排序。
- 元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过compareTo方法确定是否为重复元素。
-
红黑树:红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
-
红黑树是每个结点都带有颜色属性的二叉查找树,颜色或红色或黑色。 在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1. 结点是红色或黑色。
性质2. 根结点是黑色。
性质3. 所有叶子都是黑色。(叶子是NIL结点)
性质4. 每个红色结点的两个子结点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色结点)
性质5. 从任一节结点其每个叶子的所有路径都包含相同数目的黑色结点。
这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
是性质4导致路径上不能有两个连续的红色结点确保了这个结果。最短的可能路径都是黑色结点,最长的可能路径有交替的红色和黑色结点。因为根据性质5所有最长的路径都有相同数目的黑色结点,这就表明了没有路径能多于任何其他路径的两倍长。
因为红黑树是一种特化的二叉查找树,所以红黑树上的只读操作与普通二叉查找树相同。
当我们在对红黑树进行插入和删除等操作时,对树做了修改,那么可能会违背红黑树的性质。
为了保持红黑树的性质,我们可以对相关结点做一系列的调整,通过对树进行旋转(例如左旋和右旋操作),即修改树中某些结点的颜色及指针结构,以达到对红黑树进行插入、删除结点等操作时,红黑树依然能保持它特有的性质(五点性质)。
Set接口使用
package collections.set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 测试Set接口的使用
* 特点:1.无序、没有下标
* 2.不能重复
*/
public class Demo01 {
public static void main(String[] args) {
// 创建集合
Set<String> set = new HashSet<>();
// 1.添加数据
set.add("苹果");
set.add("华为");
set.add("小米");
set.add("小米");
System.out.println("数据个数:" + set.size());
System.out.println(set);
System.out.println("=======删除========");
// 2.删除
set.remove("华为");
System.out.println(set);
// 3.遍历
// 3.1增强for
System.out.println("=======增强for遍历========");
for (String s : set) {
System.out.println(s);
}
System.out.println("=======迭代器========");
// 3.2迭代器
Iterator<String> it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println("=======判断========");
// 4.判断
System.out.println(set.isEmpty());
System.out.println(set.contains("华为"));
}
}
结果:
数据个数:3
[苹果, 华为, 小米]
=======删除========
[苹果, 小米]
=======增强for遍历========
苹果
小米
=======迭代器========
苹果
小米
=======判断========
false
false
HashSet使用
- 存储结构:哈希表
package collections.set.hashset;
import java.util.HashSet;
import java.util.Iterator;
/**
* HashSet集合的使用
* 存储结构:哈希表(数组+链表+红黑树(JDK1.8之后多了红黑树))
*/
public class Demo01 {
public static void main(String[] args) {
// 新建集合
HashSet<String> hashSet = new HashSet<>();
// 1.添加元素
hashSet.add("liu");
hashSet.add("jia");
hashSet.add("qi");
hashSet.add("jiaqi");
hashSet.add("liu");
System.out.println(hashSet.size());
System.out.println(hashSet);
System.out.println("======删除======");
// 2.删除
hashSet.remove("liu");
System.out.println("删除之后:" + hashSet.size());
System.out.println("======增强for遍历======");
// 3.遍历
// 3.1增强for
for (String s : hashSet) {
System.out.println(s);
}
System.out.println("======迭代器遍历======");
// 3.2迭代器
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("======判断======");
// 4.判断
System.out.println(hashSet.isEmpty());
System.out.println(hashSet.contains("liu"));
}
}
结果:
4
[jia, qi, liu, jiaqi]
======删除======
删除之后:3
======增强for遍历======
jia
qi
jiaqi
======迭代器遍历======
jia
qi
jiaqi
======判断======
false
false
HashSet存储方式
- 存储过程:
- 根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空则执行第二步。
- 再执行equals方法,如果equals方法为true,则认为是重复,否则,不重复,形成链表。
package collections.set.hashset;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.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;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// // 手动重写hashCode+equals
// @Override
// public int hashCode() {
// int n1 = this.name.hashCode();
// int n2 = this.age;
//
// return n1 + n2;
// }
//
// @Override
// public boolean equals(Object obj) {
// if (this == obj) {
// return true;
// }
// if (obj == null) {
// return false;
// }
// if (obj instanceof Person) {
// Person p = (Person) obj;
// if (this.name.equals(p.name) && this.age == p.age) {
// return true;
// }
// }
// return false;
// }
//快捷键重写 Alt+insert,选择equals and hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package collections.set.hashset;
import java.util.HashSet;
import java.util.Iterator;
/**
* HashSet的使用
* 存储结构:哈希表(数据+链表+红黑树(JDK1.8之后多了红黑树))
* 存储过程:1.根据hashCode计算保存的位置,如果此位置为空,则直接保存,如果不为空则执行第二步
* 2.再执行equals方法,如果equals方法为true,则认为是重复,否则,形成链表
*/
public class Demo02 {
public static void main(String[] args) {
// 创建集合
HashSet<Person> persons = new HashSet<>();
// 1.添加数据
Person person1 = new Person("liu", 20);
Person person2 = new Person("jia", 22);
Person person3 = new Person("liujia", 21);
Person person4 = new Person("liujia", 21);
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person3); // 重复的不能添加
persons.add(person4); // 新对象重复的可以添加
// 新对象重复的可以添加进去
// 如果重写hashCode方法和equals,名字相同,年龄相同就不能加进来了
persons.add(new Person("liu", 20));
System.out.println("元素个数:"+persons.size());
System.out.println(persons);
// 2.删除操作
System.out.println("======删除======");
// person.remove(person3);
persons.remove(new Person("liu", 20)); // 能删,因为重写了hashCode方法
System.out.println("删除之后:" + persons);
// 3、遍历
// 3.1增强for
System.out.println("======增强for遍历======");
for (Person person : persons) {
System.out.println(person);
}
// 3.2迭代器
System.out.println("======迭代器遍历======");
Iterator<Person> iterator = persons.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
// 4.判断
System.out.println(persons.isEmpty());
System.out.println(persons.contains("liu"));
}
}
结果
元素个数:3
[Person{name='jia', age=22}, Person{name='liujia', age=21}, Person{name='liu', age=20}]
======删除======
删除之后:[Person{name='jia', age=22}, Person{name='liujia', age=21}]
======增强for遍历======
Person{name='jia', age=22}
Person{name='liujia', age=21}
======迭代器遍历======
Person{name='jia', age=22}
Person{name='liujia', age=21}
false
false
HashSet补充

TreeSet的使用
package collections.set.treeset;
import java.util.Iterator;
import java.util.TreeSet;
/**
* TreeSet的使用
* 存储结构:红黑树
*/
public class Demo01 {
public static void main(String[] args) {
// 创建集合
TreeSet<String> treeSet = new TreeSet<>();
// 1.添加元素
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("hello");
treeSet.add("xyz"); // 重复
System.out.println("元素个数:" + treeSet.size());
System.out.println(treeSet);
// 2.删除
System.out.println("======删除======");
treeSet.remove("xyz");
System.out.println("删除之后:" + treeSet.size());
// 3.遍历
// 3.1增强for
System.out.println("======增强for遍历======");
for (String s : treeSet) {
System.out.println(s);
}
// 3.2迭代器
System.out.println("======迭代器遍历======");
Iterator<String> it = treeSet.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
// 4.判断
System.out.println("======判断======");
System.out.println(treeSet.contains("abc"));
System.out.println(treeSet.isEmpty());
}
}
结果:
元素个数:3
[abc, hello, xyz]
======删除======
删除之后:2
======增强for遍历======
abc
hello
======迭代器遍历======
abc
hello
======判断======
true
false
复杂例子:
在Person类中重写了compareTo方法:
package collections.set.hashset;
import java.util.Objects;
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.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;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
// // 手动重写hashCode+equals
// @Override
// public int hashCode() {
// int n1 = this.name.hashCode();
// int n2 = this.age;
//
// return n1 + n2;
// }
//
// @Override
// public boolean equals(Object obj) {
// if (this == obj) {
// return true;
// }
// if (obj == null) {
// return false;
// }
// if (obj instanceof Person) {
// Person p = (Person) obj;
// if (this.name.equals(p.name) && this.age == p.age) {
// return true;
// }
// }
// return false;
// }
//快捷键重写 Alt+insert,选择equals and hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && name.equals(person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
// 先按姓名比,然后再按年龄比
@Override
public int compareTo(Person o) {
// 先比姓名
int n1 = this.getName().compareTo(o.getName());
// 再比年龄
int n2 = this.age - o.getAge();
return n1 == 0 ? n2 : n1;
}
}
package collections.set.treeset;
import collections.set.hashset.Person;
import java.util.Iterator;
import java.util.TreeSet;
/**
* 使用TreeSet保存数据
* 存储结构:红黑树
* 要求:元素必须实现Comparable接口,comPareTo()方法的返回值为0,则认为是重复元素
*/
public class Demo02 {
public static void main(String[] args) {
// 创建集合
TreeSet<Person> persons = new TreeSet<>();
Person person1 = new Person("liu", 20);
Person person2 = new Person("jia", 22);
Person person3 = new Person("liujia", 21);
Person person4 = new Person("liujia", 21);
// 1.添加元素
persons.add(person1);
persons.add(person2);
persons.add(person3);
System.out.println("元素个数:" + persons.size());
System.out.println(persons);
// 2.删除
System.out.println("========删除========");
persons.remove(person1);
// 这里不用重写 hashCode 和 equals 也可以,但是要重写compareTo
// 因为重写了compareTo的比较方式所以可以删除
// persons.remove(new Person("liujia", 21));
System.out.println(persons.size());
// 3.遍历
// 3.1 增强for
System.out.println("========增强for遍历========");
for (Person person : persons) {
System.out.println(person);
}
// 迭代器
System.out.println("========迭代器遍历========");
Iterator<Person> it = persons.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// 4.查找
System.out.println(persons.contains(person4));
System.out.println(persons.contains(new Person("liujia", 21)));
}
}
结果:
元素个数:3
[Person{name='jia', age=22}, Person{name='liu', age=20}, Person{name='liujia', age=21}]
========删除========
2
========增强for遍历========
Person{name='jia', age=22}
Person{name='liujia', age=21}
========迭代器遍历========
Person{name='jia', age=22}
Person{name='liujia', age=21}
true
true
Comparator接口
Comparator:实现定制比较(比较器),不需要再到Person里实现接口。
Comparable:可比较的,在Person里实现接口
package collections.set.treeset;
import collections.set.hashset.Person;
import java.util.Comparator;
import java.util.TreeSet;
/**
* TreeSet集合的使用
* Comparator:实现定制比较(比较器)
* Comparable:可比较的
*/
public class Demo03 {
public static void main(String[] args) {
// 创建集合,并指定比较规则
TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() { // 匿名内部类实现
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge() - o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1 == 0 ? n2 : n1;
}
});
Person person1 = new Person("liu", 20);
Person person2 = new Person("jia", 22);
Person person3 = new Person("liujia", 21);
Person person4 = new Person("zhangsan", 21);
persons.add(person1);
persons.add(person2);
persons.add(person3);
persons.add(person4);
System.out.println(persons);
}
}
结果:
[Person{name='liu', age=20}, Person{name='liujia', age=21}, Person{name='zhangsan', age=21}, Person{name='jia', age=22}]
重写的compareTo方法中是先比较年龄再比较姓名,所以年龄小的在前面,年龄一样ASCII码值小的在前面。
TreeSet案例
package collections.set.treeset;
import java.util.Comparator;
import java.util.TreeSet;
/**
要求:使用TreeSet集合实现字符串按照长度进行排序
* helloworld zhang lisi wangwu beijing xian nanjing
*/
public class Demo04 {
public static void main(String[] args) {
// 创建集合,并制定比较规则
TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1 = o1.length() - o2.length();
int n2 = o1.compareTo(o2);
return n1 == 0 ? n2 : n1;
}
});
// 添加数据
treeSet.add("helloworld");
treeSet.add("zhang");
treeSet.add("lisi");
treeSet.add("wangwu");
treeSet.add("beijing");
treeSet.add("xian");
treeSet.add("nanjing");
System.out.println(treeSet);
}
}
结果:
[lisi, xian, zhang, wangwu, beijing, nanjing, helloworld]
先比较长度,长度一样再比较ASSCII码大小。
Map体系集合

Map父接口
- 特点:
- 存储一堆数据(Key—Value),无序、无下标,键不可重复,值可重复。
- 方法:
- V put (k key,V value) // 将对象存入到集合中,关联键值。key重复则覆盖原值。
- Object get (Object key) // 根据键获取对应的值。
- Set // 返回所有Key
- Collection values() // 返回包含所有值的Collection集合。
- Set<Map.Entry<K, V>> // 键值匹配的Set集合。
其他可以查看API文档。
Map接口使用
package collections.map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map接口的使用
* 特点:
* 1.存储键值对
* 2.键不能重复,值可以重复
* 3.无序
*/
public class Demo01 {
public static void main(String[] args) {
// 创建Map集合
Map<String, String> map = new HashMap<>();
// 1.添加元素
map.put("CN", "中国");
map.put("UK", "英国");
map.put("USA", "美国");
// Key不能重复,添加重复的Key时,新的value会替换原有的value
map.put("CN", "China");
System.out.println("元素个数:" + map.size());
System.out.println(map);
// 2.删除
System.out.println("========删除========");
map.remove("USA");
System.out.println("删除之后:" + map.size());
// 3.遍历
// 3.1 keySet方法,返回值为所有的key的Set集合
System.out.println("========keySet()遍历========");
Set<String> keyset = map.keySet();
for (String key : keyset) {
// map.get() 通过键获取对应的值
System.out.println(key +"是" + map.get(key));
}
// 3.2 entrySet方法,返回值为Map.Entry:映射对、键值对,其中包含key和value,效率高于keySet()
System.out.println("========entrySet()遍历========");
Set<Map.Entry<String, String>> entries = map.entrySet();
// 内部接口加上Map.前缀
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey() + "是" + entry.getValue());
}
// 3.3简写
System.out.println("========还能这样简写!?========");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "是" + entry.getValue());
}
// 4.判断
System.out.println("========判断========");
System.out.println(map.isEmpty());
System.out.println(map.containsKey("CN"));
System.out.println(map.containsValue("美国"));
}
}
结果:
元素个数:3
{USA=美国, UK=英国, CN=China}
========删除========
删除之后:2
========keySet()遍历========
UK是英国
CN是China
========entrySet()遍历========
UK是英国
CN是China
========还能这样简写!?========
UK是英国
CN是China
========判断========
false
true
false
- entrySet() 效率高于 keySet()。
Map集合的实现类
HashMap【重点】:
- JDK1.2版本,线程不安全,最好在单线程下使用,运行效率快;允许用null作为key或是value。
- 默认初始容量:16
Hashtable:
- JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。现在已经不再使用了。
Properties:
- Hashtable的子类,要求key和value都是String,通常用于配置文件的读取,在后面的I/O流会遇到。
HashMap集合
JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value。
存储结构:哈希表(数组+链表+红黑树(JDK1.8之后))
HashMap的使用
Student类重写hashCode和equals方法
package collections.map.hashmap;
import java.util.Objects;
public class Student {
private String name;
private int stuNo;
public Student() {
}
public Student(String name, int stuNo) {
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNo == student.stuNo && name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNo);
}
}
HashMap使用key的hashCode和equals比较作为判断元素是否重复的依据,重写改变判断依据。
package collections.map.hashmap;
import java.util.HashMap;
import java.util.Map;
/**
* HashMap集合的使用
* 存储结构:哈希表(数组+链表+红黑树(JDK1.8以后))
* 使用key的hashCode和equals比较作为判断元素是否重复的依据
*/
public class Demo01 {
public static void main(String[] args) {
// 创建集合
HashMap<Student, String> students = new HashMap<>();
// 1.添加元素
Student s1 = new Student("liu", 1);
Student s2 = new Student("jia", 2);
Student s3 = new Student("qi", 3);
students.put(s1, "刘");
students.put(s2, "嘉");
students.put(s3, "奇");
// 加不进去,键不允许重复,值可以重复
students.put(s3, "嘉奇");
// 能加进去,要想实现姓名和学号一样就加不进去,就要重写hashCode和equals方法咯
students.put(new Student("jia", 2), "嘉2");
System.out.println("元素个数:" + students.size());
System.out.println(students);
// 2.删除
System.out.println("========删除=============");
students.remove(s1);
System.out.println("删除之后:" + students);
// 3.遍历
// 3.1keySet
System.out.println("========keySet遍历=============");
for (Student key : students.keySet()) {
System.out.println(key.toString() + ":" + students.get(key));
}
// 3.2entrySet
System.out.println("========entrySet遍历=============");
for (Map.Entry<Student, String> entry : students.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 4.判断
System.out.println("========判断=============");
System.out.println(students.containsKey(new Student("liu", 1)));
System.out.println(students.containsValue("嘉2"));
}
}
结果:
元素个数:3
{Student{name='jia', stuNo=2}=嘉2, Student{name='liu', stuNo=1}=刘, Student{name='qi', stuNo=3}=嘉奇}
========删除=============
删除之后:{Student{name='jia', stuNo=2}=嘉2, Student{name='qi', stuNo=3}=嘉奇}
========keySet遍历=============
Student{name='jia', stuNo=2}:嘉2
Student{name='qi', stuNo=3}:嘉奇
========entrySet遍历=============
Student{name='jia', stuNo=2}:嘉2
Student{name='qi', stuNo=3}:嘉奇
========判断=============
false
true
HashMap源码分析
数组默认初始容量为16(1 << 4 1左移4位 1 * (2^4) 即16)
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
数组最大容量 2 ^ 30
static final int MAXIMUM_CAPACITY = 1 << 30;
默认的加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
默认的树化阈值:JDK1.8后加入红黑树,当链表的长度大于8,数组的长度大于等于64时,链表将会调整为红黑树,进一步提高查找效率。
static final int TREEIFY_THRESHOLD = 8;
static final int MIN_TREEIFY_CAPACITY = 64;
当链表的长度小于6,就将该树调整为链表:
static final int UNTREEIFY_THRESHOLD = 6;
键值对其实就是一个个Node
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
table:保存的哈希表,刚创建好时table = null;
transient Node<K,V>[] table;
元素的个数:刚创建好时size= 0;
transient int size;
构造方法(给加载因子赋值0.75)
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
put方法:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
总结:
- HashMap刚创建时,没有添加任何元素,table为null,容量为0,当添加第一个元素时,table容量调整为16。
- 当数组元素大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍,目的是减少调整元素的个数。比如,当元素的数量超过12时,数组的容量就会调整为32。
- JDK1.8后当每个链表的长度大于8,且数组元素的个数大于等于64时,会调整为红黑树,目的是提高代码执行效率。
- JDK1.8后当链表的长度小于6时,调整成链表。
- JDK1.8之前,链表是头插入,JDK1.8以后是尾插入。
HashMap和HashSet的区别
public HashSet() {
map = new HashMap<>();
}
实际上HashSet底层用的就是HashMap。
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
实际上HashSet用的就是HashMap中的key来保存数据。
Hashtable和Properties
Hashtable已经不用了,Priperties在后边的I/O流部分会进一步解释。
TreeMap集合
存储结构:红黑树
TreeMap的使用
在Student类中重写了compareTo方法,比较学号stuNo
package collections.map.hashmap;
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int stuNo;
public Student() {
}
public Student(String name, int stuNo) {
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNo == student.stuNo && name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNo);
}
@Override
public int compareTo(Student o) {
int n2 = this.stuNo - o.getStuNo();
return n2;
}
}
如果不重写方法也可以在新建集合时定制比较:
// 新建集合 定制比较
TreeMap<Student, String> treeMap = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n1 = o1.getStuNo() - o2.getStuNo();
return n1;
}
});
package collections.map.treemap;
import collections.map.hashmap.Student;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
/**
* TreeMap的使用
* 存储结构:红黑树
*/
public class Demo01 {
public static void main(String[] args) {
// 新建集合
// TreeMap<Student, String> treeMap = new TreeMap<>();
// 新建集合 定制比较
TreeMap<Student, String> treeMap = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n1 = o1.getStuNo() - o2.getStuNo();
return n1;
}
});
// 1.添加元素 要实现Comparable接口
Student s1 = new Student("liu", 1);
Student s2 = new Student("jia", 2);
Student s3 = new Student("qi", 3);
treeMap.put(s1, "北京");
treeMap.put(s2, "上海");
treeMap.put(s3, "江苏");
// 加不进去,但是会替换掉value
treeMap.put(new Student("qi", 3), "南京");
System.out.println("元素个数:" + treeMap.size());
System.out.println(treeMap);
// 2.删除
System.out.println("========删除=============");
treeMap.remove(s3);
// treeMap.remove(new Student("qi", 3)); 能删除,因为compareTo比较的是学号
System.out.println("删除之后:" + treeMap.size());
// 3.遍历
// 3.1keySet
System.out.println("========keySet()遍历=============");
for (Student key : treeMap.keySet()) {
System.out.println(key + ":" + treeMap.get(key));
}
// 3.2entrySet
System.out.println("========entrySet()遍历=============");
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 4.判断
System.out.println(treeMap.containsKey(new Student("liu", 1)));
System.out.println(treeMap.containsValue("南京"));
}
}
结果:
元素个数:3
{Student{name='liu', stuNo=1}=北京, Student{name='jia', stuNo=2}=上海, Student{name='qi', stuNo=3}=南京}
========删除=============
删除之后:2
========keySet()遍历=============
Student{name='liu', stuNo=1}:北京
Student{name='jia', stuNo=2}:上海
========entrySet()遍历=============
Student{name='liu', stuNo=1}:北京
Student{name='jia', stuNo=2}:上海
true
false
TreeMap和TreeSet的关系
TreeSet的底层其实就是调用TreeMap
public TreeSet() {
this(new TreeMap<>());
}
TreeSet的add方法调用的就是map.put()方法
public boolean add(E e) {
return m.put(e, PRESENT)==null;
}
Collections工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法。
- 方法:
- public static void reverse(List<?> list) // 反转集中元素的顺序
- public static void shuffle(List<?> list) // 随机重置集合元素的顺序
- public static void sort(List list) // 升序排序(元素类型必须实现Comparable接口)
package collections;
import java.util.*;
/**
* Collections工具类的使用
*/
public class Demo01 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(15);
list.add(30);
list.add(25);
list.add(5);
// 1.sort排序 (默认是升序,从小到大排序)
System.out.println("==========sort排序==========");
System.out.println("排序之前:" + list);
Collections.sort(list); // 也可以自定义排序规则
System.out.println("排序之后:" + list);
// 2.binarySearch 二分查找 输出下标 没找到则返回负数
System.out.println("==========binarySearch==========");
int i = Collections.binarySearch(list, 15);
System.out.println(i);
// 3.copy 复制
System.out.println("==========copy==========");
List<Integer> list1 = new ArrayList<>();
// 先令list1集合大小和list集合大小一致
for (int j = 0; j < list.size(); j++) {
list1.add(0);
}
// 直接复制会报错,这里的copy方法使用前提是两个集合大小一样,显然没有元素的list1大小为0
Collections.copy(list1, list);
System.out.println(list1);
// 4.reverse 反转
System.out.println("==========reverse==========");
Collections.reverse(list1);
System.out.println("反转之后:" + list1);
// 5.shuffle 打乱
System.out.println("==========shuffle==========");
Collections.shuffle(list1);
System.out.println("打乱之后:" + list1);
// 6.补充:
// 6.1 list集合转数组
System.out.println("==========list集合转数组==========");
/* 这里的长度设置如果小于list长度,则返回的数组长度是一样的;
大于list长度,返回的数组长度就会是设置的长度 */
Integer[] integers = list.toArray(new Integer[0]);
System.out.println("设置的数组长度:" + integers.length);
System.out.println(Arrays.toString(integers));
System.out.println("==========设置的长度大于list==========");
// 设置的数组长度大于list,则默认为null
Integer[] integers1 = list.toArray(new Integer[10]);
System.out.println("设置的数组长度:" + integers1.length);
System.out.println(Arrays.toString(integers1));
// 6.2 数组转list集合
System.out.println("==========数组转list集合==========");
String[] names = {"张三", "李四", "王五"};
// 转完的集合是一个受限集合,不能添加、删除元素;长度是固定的
List<String> list2 = Arrays.asList(names);
System.out.println(list2);
System.out.println("==========基本类型的数组转成集合需要修改为包装类型==========");
// 基本类型的数组转换后 list中是一个数组,只有一个数据
// int[] nums = {100, 200, 300, 400, 500};
// List<int[]> list3 = Arrays.asList(nums);
Integer[] nums = {100, 200, 300, 400, 500};
List<Integer> list3 = Arrays.asList(nums);
System.out.println(list3);
}
}
结果:
==========sort排序==========
排序之前:[20, 15, 30, 25, 5]
排序之后:[5, 15, 20, 25, 30]
==========binarySearch==========
1
==========copy==========
[5, 15, 20, 25, 30]
==========reverse==========
反转之后:[30, 25, 20, 15, 5]
==========shuffle==========
打乱之后:[30, 20, 15, 5, 25]
==========list集合转数组==========
设置的数组长度:5
[5, 15, 20, 25, 30]
==========设置的长度大于list==========
设置的数组长度:10
[5, 15, 20, 25, 30, null, null, null, null, null]
==========数组转list集合==========
[张三, 李四, 王五]
==========基本类型的数组转成集合需要修改为包装类型==========
[100, 200, 300, 400, 500]
集合总结
-
集合的概念:
- 对象的容器,和数组类似(但长度可以改变),定义了多个对象进行操作的常用方法。
-
List集合
- 有序、有下标、元素可以重复。(ArrayList(存储结构:数组)、LinkedList(存储结构:双向链表)、Vector)
-
Set集合
- 无序、无下标、元素不可重复。(HashSet(存储结构:哈希表:数组+链表+红黑树)、TreeSet(存储结构:红黑树))
-
Map集合
- 存储一堆数据,无序、无下标、键不可以重复,值可以重复。(HashMap(哈希表)、HashTable、TreeMap(红黑树))
-
Collections:
- 集合工具类,定义了除了存取以外的集合常用方法
磕磕绊绊的也是挤着时间学完了集合这一块,理论知识还需巩固,实践经验还没有… 继续加油吧!