Java集合基础
集合简介
概述
什么是集合呢?集合规范而言是一类引用数据类型。当我们有多个数据需要存储的时候我们一般使用数组来存储。但数组有一个很不讨喜的特点就是数组在初始化的时候其长度就被定死了,不可改变。其存储的数量不变,因此在使用的时候一般用于存储数量不变的场景中。当遇到存储数量需要改变的时候数组就显得不太合适。因此我们引入了集合!
作用
集合,可以保存数量不确定的数据,更重要的是,集合能保存具有映射关系的数据。集合中只能保存对象(对象的引用变量),而数组元素可以是基本数据类型的值,也可以是对象(对象的引用变量)。
集合类
集合类,主要由两个接口派生而来:Collection 和 Map
Collection接口
其子类关系图如下:
Collection 接口派生的子接口:Set 和 List 接口
Java 提供的队列实现:Queue(类似 List)
Map接口
其子类关系图如下:
Map 实现类,用于保存具有映射关系的数据,也就是 key-value对,但 key 不会重复,一般需要通过 key 来找到对应的 value 值。
Collection集合
Collection本身是接口不能实例化对象,我们使用时需要使用向上转型,使用接口接收子类对象来操作Collection接口中特有的方法。
Collection中常用方法
方法 | 作用 |
---|---|
add(Object obj) | 在集合中,添加一个元素 |
addAll(Collection c) | 把集合 c 中的所有元素添加到指定的集合中。 |
clear() | 清除集合中所有元素。 |
contains(Object obj) | 常用于判断集合中是否包含指定元素。 |
containsAll(Collection c) | 常用于判断某集合中是否包含指定的 c 集合中的所有元素。 |
isEmpty() | 判断集合是否为空。 |
iterator() | 获取一个 Iterator 迭代器对象,用来遍历集合里的元素。 |
remove(Object obj) | 删除指定元素 |
removeAll(Collection c) | 在某集合中删除指定 c 集合中包含的所有元素。 |
size() | 获取集合中元素的个数。length() 获取长度 |
toArray() | 把集合转成一个数组,集合元素会变成数组元素。 |
这些常用的方法,都可以通过开发者 API 文档中找到,非常多但不建议死记硬背,无非就是添加对
象、删除对象、清空集合、判断集合是否为空等几个经典动作。建议,初学阶段要多去了解每个方法
的作用,才能更好地知道都有哪些功能将来能用到实际开发中。
演示用例
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo {
public static void main(String[] args) {
//注意导包需要导入java.util包下
//Collection本身是 无序可重复
//向上转型 调用共有的方法和属性 以实现子类ArrayList()为例
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
//添加 add() 只能添加引用数据类型 因此实际添加的是基本数据类型的包装类类型
c1.add("权力的游戏");
c1.add(true);
c1.add(188);
c1.add(222);
c2.add(16.5);
c2.add(188);
c2.add(222);
//直接添加集合内的数据 addAll
c1.addAll(c2);
//集合内的数据可以直接打印输出
System.out.println(c1);
//集合长度size()
System.out.println(c1.size());
//判断
//判断此集合是否为空 为空返回true
System.out.println(c1.isEmpty());
//判断此元素是否存在于此集合contains() 存在返回true
System.out.println(c1.contains(188));
//判断此是否存在于此集合contains() 存在返回true
System.out.println(c1.containsAll(c2));
//移除单个元素和移除集合
//单个移除 移除发现的第一个
c1.remove(188);
System.out.println(c1);
//集合移除 移除此集合中所有的元素 包含原集合中重复的元素
c1.removeAll(c2);
System.out.println(c1);
//清空全部元素 clear()
c1.clear();
System.out.println(c1);
//转换为数组 toArray()
System.out.println(c2.toArray());
Object[] object = c2.toArray();
System.out.println(object[1]);
//遍历 因为Collection本身是无序的 不能通过下标定(索引)定位元素 故遍历一般有三种方式
System.out.println("foreach-------------------------------------------------------");
//foreach
for(Object obj:c2) {
System.out.println(obj);
}
System.out.println("迭代器-----------------------------------------------------------");
//迭代器
//1.得到迭代器
Iterator i2 = c2.iterator();
//执行过程 1.判断游标后面是否存在元素 存在返回ture
while(i2.hasNext()) {
//执行过程 2.返回游标的下一个元素 并将游标后移
System.out.println(i2.next());
}
System.out.println("Lambda--------------------------------------------------");
//Lambda 表达式遍历集合
c2.forEach(obj -> System.out.println(obj));
}
}
List集合
List 是一个元素有顺序、元素可重复的集合,集合中的每个元素都有对应的索引。
List 可以针对索引来操作集合的元素,比如插入、替换和删除集合元素。
List本身也是一个接口不可被实例化 因此需要用到ArrayList类或Vector类来实现。
ArrayList和Vector实现类
特点
☼它们都是基于数组实现的 List 类,封装了一个动态的、允许再分配的 Object[] 数组,主要使用initialCapacity 参数来设置该数组的长度,当添加的元素数量过多的话,则 initialCapacity 会自动增长,默认长度是 10。
☼有时候需要注意性能问题,如果向这两个集合中添加大量元素时,可用 ensureCapacity(int minCapacity) 方法一次性地增加initialCapacity,这样可以减少重分配的次数,提高新能。
☼它们也可以使用 ensureCapacity(int minCapacity) 和 trimToSize() 方法来重新分配 Object[] 数组。
☼Vector 是一个比较老旧的集合,是 ArrayList 的前身,有很多缺点,不使用。
☼ArrayList 是线程不安全的,如果多个线程访问&修改了 ArrayList 集合,就需要手动保证集合的同步
性。
☼Vector 是线程安全的,所以性能会比 ArrayList 稍低,哪怕是线程安全也不推荐使用。后面,我们可以
用 Collections 工具类来讲 ArrayList 变成线程安全的。
☼ArrayList相对比于其父类接口中多出的显著特点就是有顺序 有无顺序主要体现在是否可以通过下标来操作数据
☼因此ArrayList中特有的方法主要也是根据有序这个特点来的
ArrayList总结
底层数组集合 遍历快、访问元素的速度也快、插入和删除速度慢 、不同步(线程不安全)
演示实例
import java.util.ArrayList;
import java.util.ListIterator;
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList l1 = new ArrayList();
l1.add(1);
l1.add(2);
l1.add(3);
l1.add(4);
//通过下标获取数据get()
System.out.println(l1.get(1));
//替换 将指定位置的数据更改
l1.set(3, 5);
System.out.println(l1);
//返回元素第一次出现的下标值indexof()
System.out.println(l1.indexOf(5));
//通过下标删除数据 删除完成后返回的是该下标数据的值
//l1.remove(3);
System.out.println(l1.remove(3));
System.out.println(l1);
//注意此时仍然可以使用数据本身来删除 注意传入整数数据时要进行类型转换 删除完成后返回true
l1.remove((Integer)1);
System.out.println(l1);
l1.add(4);
l1.add(5);
l1.add(6);
//可以倒序输出了 for循环 和迭代器 演示
System.out.println("for--------------------------------------------------");
for(int i=l1.size();i>0;i--) {
System.out.println(l1.get(i-1));
}
System.out.println("迭代器--------------------------------------------");
//需要先正序才能倒序
System.out.println("正序-------------------------");
ListIterator listIterator = l1.listIterator();
while(listIterator.hasNext()) {
System.out.println(listIterator.next());
}
System.out.println("倒叙-------------------------");
while(listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
}
}
泛型
是什么 简单讲在集合后面加入<数据类型> 便是泛型了
ArrayList<String> l1 = new ArrayList<String>();//使用泛型来限制集合可传入的数据类型
作用
用于限制集合,存储类型 用了泛型之后只能存储同种类型数据。
泛型除了可以在集合中使用之外 也可以在类和方法中使用
好处
安全性更高 消除了绝大部分类型转换问题 增加了维护性 可读性
使用示例
import java.util.ArrayList;
import java.util.ListIterator;
public class GenericDemo{
public static void main(String[] args) {
//使用泛型来限制集合可传入的数据类型
ArrayList<String> book = new ArrayList<String>();
book.add("Java程序设计");
book.add("C语言入门");
book.add("Python大法好");
book.add("Bug修改入门");
book.add("追求测试小姐姐话术");
//可以直接用于赋值运算 不需要考虑复杂的类型问题 简单易维护
String s = book.get(4)+book.get(3);
System.out.println(s);
//foreach可以使用特点类型了 不需要再使用Object了
for(String str : book) {
System.out.println(str);
}
ListIterator<String> listIterator = book.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
}
}
长度不变的List
Arrays 类的 asList(Object… a) 方法,可以把一个数组或指定个数的对象转成一个 List 集合,这个集合
既不是 ArrayList 实现类的实例,也不是 Vector 实现类的实例,而是 Arrays 的内部类 ArrayList 的实
例。
Arrays.ArrayList 是一个固定长度的 List 集合,只能访问元素,不能添加和删除集合中的元素。
示例
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
public class ArraysDemo {
public static void main(String[] args) {
//asList(T... a)
//... 表示可以存放多个元素
//返回的这个集合 长度不可变 不能添加不能删除
List<String> bookList = Arrays.asList("基督山伯爵","追风筝的人","资治通鉴","五年高考三年模拟");
System.out.println(bookList);
//getClass()获取对象的实现类
System.out.println(bookList.getClass());
//ForEach() 遍历集合
bookList.forEach(System.out::println);
}
}
Set集合
Set 集合,元素是无序的,而且不能有重复的。
常用的实现子类有HashSet、LinkedHash、SetTreeSet
HashSet实现类
特点
◕添加的元素是无序的、不可重复。
◕HashSet 不是同步的,如果多个线程同时访问一个 HashSet,比如在修改时,一定要手动通过代码来保证同步,也就是保证安全。
◕集合元素值可以是 null。
主要特点便是插入的数据不可重复
示例
import java.util.HashSet;
import java.util.Iterator;
public class HashsetDemo {
public static void main(String[] args) {
//Hashset 存储数据唯一(不可重复) 无序
HashSet<String> student = new HashSet<String>();
student.add("张三");
student.add("张三");//重复的数据不会被添加
student.add("李四");
student.add("王五");
student.add("宋六");
System.out.println(student);
Iterator<String> iterator = student.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
LinkedHashSet实现类
特点
••LinkedHashSet 从名字上看,跟“链式”有关,它也是根据元素的 hashCode 值来决定元素的存储位置,但还多使用链表来维护元素的顺序。
••访问它的时候,会根据元素的添加顺序来访问集合中的元素,有个好处,访问时的性能会很好。但,就因为是链式的结构,在插入数据的时候,性能略差于 HashSet,插入元素时不建议使用。
总结
访问多使用LinkedHashSet 插入多使用HashSet
示例
import java.util.LinkedHashSet;
public class LinkHashSetDemo {
public static void main(String[] args) {
//无序唯一
//链表结构 与hashset相比 访问快 插入慢
LinkedHashSet<String> teacher = new LinkedHashSet<String>();
teacher.add("张老师");
teacher.add("张老师");//重复数据不会被插入
teacher.add("王老师");
teacher.add("李老师");
teacher.add("高老师");
teacher.add("刘老师");
System.out.println(teacher);
teacher.remove("高老师");//删除高老师
for(String str:teacher) {
System.out.println(str);
}
}
}
存储对象 并修改重复判断标准
集合可以存储引用数据类型自然可以存储对象
那么我们常规判断对象是否相同是是判断对象的内存地址是否相同
在Mpa中也是如此 但是有时这种判断不符合我们的显示需求
以员工类举例而言 我们的判断标准一般是以员工编号为准
往 HashSet 集合中添加一个元素的时候,默认调用 hashCode() 方法得到该对象的 hashCode 值,用
于决定该对象在 HashSet 中存放的位置。
如果两个元素,通过 equals() 方法比较返回 true,但 hashCode() 返回的值不一样,说明两个元素是不
一样的,则允许添加。
所以,HashSet 集合判断两个元素是否相等,就是通过 equals() 方法比较,还有 hashCode 值也一起
比较。
因此我们首先需要重写员工类中的equals()方法比较员工编号的值 然后需要重写hashCode()方法返回固定的值
示例
import java.util.HashSet;
import java.util.Iterator;
public class PersonnelDemo {
String number;//员工编号
String name;
int age;
//使用快捷方式生成构造函数 用于赋予初始值
public PersonnelDemo(String number, String name, int age) {
super();
this.number = number;
this.name = name;
this.age = age;
}
public PersonnelDemo() {
}
//重写equlas()将比较对象由变为员工对象
@Override
public boolean equals(Object obj) {
// TODO 自动生成的方法存根
PersonnelDemo personnel = (PersonnelDemo)obj;
return this.number.equals(personnel.number);
}
//重写hashcode() 确定返回的值都唯一
@Override
public int hashCode() {
// TODO 自动生成的方法存根
return 1000;
}
//快捷toString 方便打印输出
@Override
public String toString() {
return "PersonnelDemo [number=" + number + ", name=" + name + ", age=" + age + "]";
}
public static void main(String[] args) {
PersonnelDemo zhangsan= new PersonnelDemo("001","张三",28);
PersonnelDemo zhangsan2= new PersonnelDemo("001","张三",28);//在正常存储的时候因为是两个对象 会存储成功 为了满足需求需重写 equals() hashcode()
PersonnelDemo lisi= new PersonnelDemo("002","李四",23);
PersonnelDemo wangwu= new PersonnelDemo("003","王五",23);
PersonnelDemo songliu= new PersonnelDemo("004","宋六",26);
HashSet<PersonnelDemo> h = new HashSet<PersonnelDemo>();
h.add(zhangsan);
h.add(zhangsan2);//不会存储成功
h.add(lisi);
h.add(wangwu);
h.add(songliu);
System.out.println(h);
System.out.println("迭代器输出-------------------------------------------");
//遍历
Iterator< PersonnelDemo> iterator = h.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
TreeSet实现类
有个强悍的特点,它可以进行排序(并不代表TreeSet是有序的),因为 TreeSet 是 SortedSet 接口的实现类。
TreeSet 可保证元素处于排序的状态,所以 TreeSet 采用的是红黑树的数据结构来存储集合元素的。
排序规则有:自然排序(默认)和定制排序。
示例 (自然排序)
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
//存储红黑二叉树数据结构 会对数进行排序存储 但是依然是无序的
TreeSet ts = new TreeSet();
ts.add(16);
ts.add(7);
ts.add(4);
ts.add(12);
ts.add(17);
System.out.println(ts);
for(Object object : ts) {
System.out.println(object);
}
}
}
定制排序(了解几乎几乎不用)
如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 对象与该 TreeSet
集合关联,由此对象负责集合元素的排序逻辑。因为它是一个函数式接口,可以使用 Lambda 表达式来
替代 Comparator 对象。
示例(定制降序)
import java.util.TreeSet;
class M {
int age;
public M(int age) {
this.age = age;
}
public String toString() {
return "M [age:" + age + "]";
}
}
public class TreeSetDemoTwo {
public static void main(String[] args) {
// 此处 Lambda 表达式的目标类型是 Comparator
TreeSet ts = new TreeSet((o1, o2) -> {
// 此处,将两个变量直接强转
M m1 = (M) o1;
M m2 = (M) o2;
// 根据M对象的age属性来决定大小,age越大,M对象反而越小
return m1.age > m2.age ? -1 : m1.age < m2.age ? 1 : 0;
});
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(9));
System.out.println(ts);
}
}
EnumSet实现类
❤EnumSet 中的元素都必须是指定枚举类型的枚举值,EnumSet 以枚举值定义顺序来决定集合元素的具体顺序。
❤EnumSet 内部主要以位向量的形式存储,特点是非常紧凑、高效、占用内存小、运行效率很好,所以执行速度非常快,特别适合批量操作。
❤EnumSet 不能添加 null,否则会报空指针异常。
❤EnumSet 需要使用类方法来创建对象实例。
示例
import java.util.EnumSet;
import java.util.Iterator;
public class EnumSetDemo {
//创建一个Number枚举
enum Number{ONE,TWO,THREE,FOR}
//allof() 获取所有元素
public static void main(String[] args) {
EnumSet es= EnumSet.allOf(Number.class);
System.out.println(es);
//迭代器循环输出
System.out.println("迭代器------------------------");
Iterator<Number> iterator = es.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
//noneOf创建一个空的EnumSet集合
EnumSet esTwo= EnumSet.noneOf(Number.class);
esTwo.add(Number.ONE);//添加单个元素
System.out.println(esTwo);
}
}
Queue 集合
Queue 用于模拟队列数据结构,主要是元素有“先进先出 FIFO”的特性。队列不允许随机访问队列中的
元素。
Queue 接口有 PriorityQueue 实现类和 Deque 接口,其中 Deque 接口是一个“双端队列”,可以从两
端添加、删除元素,所以 Deque 的实现类既可当成队列使用,也可以当成堆栈使用。
PriorityQueue 实现类
它主要是一个“比较标准”的队列实现类,而不是“完全标准”。它保存队列元素的顺序并不是按加入队列
的顺序,而是按队列元素的大小进行重新排列,一般使用 peek() 或者 poll() 方法取出元素的时候,取的
是队列中最小的元素。
PriorityQueue 不允许插入 null 元素。
示例
import java.util.PriorityQueue;
public class PriorityQueueDemo {
public static void main(String[] args) {
PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
//依次加入几个元素
pq.add(2);
pq.add(6);
pq.add(1);
pq.add(7);
// 输出pq队列,并不是按元素的加入顺序排列
System.out.println(pq);
// 访问队列第一个元素,其实就是队列中最小的元素:1
System.out.println(pq.poll());
}
}
输出[3, 16, 20, 24]
Deque 接口和 ArrayDeque 实现类
ArrayDeque 是一个基于数组实现的双端队列,创建 Deque 时同样可指定一个 numElements 参数,
该参数用于指定 Object[] 数组的长度,如不指定,默认为 16。
LinkedList 实现类
LinkedList 是一个功能十分强的集合类,可以根据索引来随机访问集合中的元素,可以当成双端队列来
使用,因此可以被当做栈来用,也可以当成队列来使用。
LinkedList 与 ArrayList、ArrayDeque 的实现机制不同:
ArrayList、ArrayDeque 内部以数组的形式来保存集合中的元素,因此随机访问集合元素时有较好
的性能。
LinkedList 内部以链表的形式来保存集合中的元素,因此随机访问集合元素时性能较差,但在插
入、删除元素时性能比较出色。
后面的常用方式:先把某些数据,转成一个 list 集合,然后再转成一个 linkedList 集合,拆开操作完成
之后,再组装回来。
Map集合
概述
Map 集合,也常被称为字典,因为它主要用于保存具有映射关系的数据,有 key,有 value,==
具体关系:key - value==。所以 Map 中保存两组值,分别是 key 和 value,都可以保存任何引用类
型的数据。
Map 中的 key 不能重复,要根据唯一的 key 找到对应的 value,集合中任何两个 key 使用
equals() 方法进行比较都会返回 false。
Map 与 Set 的关系
如果把 Map 中所有的 key 放在一起来看,就是一个 Set 集合,因为元素不允许重复、没有顺序,Map
中的 key 刚好满足这个条件。
Map 中的 keySet() 方法可以返回一个 Set 集合,元素就是 Map 集合中所有的 key,此方法比较常
用。
Map 的 key 集和 Set 集合中元素的存储形式非常相似,甚至名字都相似。
Set 集合中是单个元素,Map 集合中是 key-value 对,如果把 key-value 揉成一个整体来看的话,我们
完全可以将 Map 集合当做 Set 集合来看,它们的关系是如此的微妙。
Map 提供了一个 Entry 内部类来封装 key-value 对,而计算 Entry 存储时只考虑 Entry 封装的
key。
Map 与 List 的关系
如果把 Map 中所有的 value 放在一起,就是一个 List 集合,因为元素之间可以重复、有顺序、可以根
据索引来查找。不过 Map 中不是通过整数值来当作索引的,而是另外一个对象作为索引。获取值,主
要通过该元素的 key 索引。
HashMap和Hashtable
概述
它们其实跟之前介绍的 ArrayList 和 Vector 是一样的概念,其实 Hashtable 是一个比较老的 Map 实现
类,不建议使用了。
Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的实现,所以 HashMap 比
Hashtable 的性能会更好些;
如果有多个线程访问同一个 Map 对象时,使用 Hashtable 会更好。
Hashtable 不能用 null 作为 key 和 value,会引发控制异常,但 HashMap 可以。
如果需要线程安全的 Map 实现类,不建议使用 Hashtable 了,可以用 Collections 工具类来处理即
可。
为了在它们中存储、获取对象,用作 key 的对象必须实现 hashCode() 方法和 equals() 方法。
判断两个 key 是否相等:两个 key 通过 equals() 方法比较返回 true,两个 key 的 hashCode 值也相
等。
Hashtable 判断两个 value 是否相等:只要两个对象通过 equals() 方法比较返回 true 即可。
HashMap基础使用
无非增、删、改、查
可以根据键来删除 修改值 得到值
直接上代码
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashDemoMap {
public static void main(String[] args) {
HashMap<Integer,String> user = new HashMap<Integer,String>();
//map 集合键不允许重复 值允许重复
user.put(1,"李四");
user.put(1,"张三");//键不允许重复此时会自动修改键中所对应的数据
user.put(2,"张三");//值允许重复
user.put(3,"王五");
user.put(4,"宋柳");
user.put(5,"刘其");
user.put(6,"周八");
System.out.println(user);
//删除 根据键删除数据
user.remove(1);
//替换
user.replace(2, "李四");
System.out.println(user);
//清空集合
//user.clear();
//根据键得到值
System.out.println(user.get(2));
}
}
HashMap两种遍历方式
第一种将键转换为set集合的方法一般用它
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashDemoMap {
public static void main(String[] args) {
HashMap<Integer,String> user = new HashMap<Integer,String>();
//map 集合键不允许重复 值允许重复
user.put(1,"李四");
user.put(1,"张三");//键不允许重复此时会自动修改键中所对应的数据
user.put(2,"张三");//值允许重复
user.put(3,"王五");
user.put(4,"宋柳");
user.put(5,"刘其");
user.put(6,"周八");
System.out.println(user);
//删除 根据键删除数据
user.remove(1);
//替换
user.replace(2, "李四");
System.out.println(user);
//清空集合
//user.clear();
//根据键得到值
System.out.println(user.get(2));
//遍历集合 1
//Map中没有迭代器 但是却提供的将键转换为set集合的方法
Set<Integer> s1 = user.keySet(); //将map中的值转换为set集合
System.out.println(s1);
System.out.println("============迭代器==========");
//迭代器
Iterator<Integer> iterator = s1.iterator();
while(iterator.hasNext()) {
int uId=iterator.next();
System.out.println("键:"+uId+" 值:"+user.get(uId));
}
System.out.println("================foreach===========");
//forecah
for(Integer uId : s1) {
System.out.println("键:"+uId+" 值:"+user.get(uId));
}
}
}
第二种 entrySet返回键值对 Map.Entry<Integer, String> 理解成一种类型即可 不常用
除此之外我们还能将map中的值转换成collection集合
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashDemoMap {
public static void main(String[] args) {
HashMap<Integer,String> user = new HashMap<Integer,String>();
//map 集合键不允许重复 值允许重复
user.put(1,"李四");
user.put(1,"张三");//键不允许重复此时会自动修改键中所对应的数据
user.put(2,"张三");//值允许重复
user.put(3,"王五");
user.put(4,"宋柳");
user.put(5,"刘其");
user.put(6,"周八");
System.out.println(user);
//删除 根据键删除数据
user.remove(1);
//替换
user.replace(2, "李四");
System.out.println(user);
//清空集合
//user.clear();
//遍历集合2
//entrySet返回键值对 Map.Entry<Integer, String> 理解成一种类型即可
Set<Map.Entry<Integer, String>> s2= user.entrySet();
System.out.println(s2);
System.out.println("====迭代器=====");
Iterator<Map.Entry<Integer, String>> iterator2 = s2.iterator();
while(iterator2.hasNext()) {
Map.Entry<Integer, String> userName = iterator2.next();
System.out.println("entry迭代器键:"+userName.getKey()+" ||entry迭代器值:"+userName.getValue());
}
System.out.println("===========foreach=============");
for(Map.Entry<Integer,String> userName : s2) {
System.out.println("键:"+userName.getKey()+" 值:"+userName.getValue());
}
//除此之外我们还能将map中的值转换成collection集合
Collection<String> values = user.values();
System.out.println(values);
}
}
HashMap因为篇幅有限不展开面试讲解了 只说基础用法 HashMap的复杂用法和源码将会伴随你的每一次跳槽 。。。。
LinkedHashMap
LinkedHashMap 也是用双向链表来维护 key-value 对的顺序,也就是 key 的顺序,该链表负责维护Map 的迭代顺序,迭代顺序与 key-value 对的插入顺序保持一致。
LinkedList 因为需要维护元素的插入顺序,因此性能会比 HashMap 的稍低,但又因为它是链表结构来维护内部顺序,在迭代访问 Map 中全部元素时,性能较好。
使用 Properties 读写属性数据&文件
Properties 在处理属性文件时特别好用,项目开发中常用。
Properties 能把 Map 对象的 key-value 写入属性文件中,格式:属性名=属性值
示例
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;
public class ProUtilsDemo {
public static void main(String[] args) {
Properties properties = new Properties();
properties.setProperty("1", "张三");
properties.setProperty("2", "李四");
properties.setProperty("3", "王五");
System.out.println(properties);
//写入文件
try {
properties.store(new FileOutputStream("src/user.properties"),"pp");
}catch (FileNotFoundException e) {
// TODO: handle exception
}catch (IOException e) {
// TODO: handle exception
}catch (Exception e) {
// TODO: handle exception
}
//读取文件
Properties properties2 = new Properties();
try {
properties2.load(new FileInputStream("src/user.properties"));
}catch (FileNotFoundException e) {
// TODO: handle exception
}catch (IOException e) {
// TODO: handle exception
}catch (Exception e) {
// TODO: handle exception
}
System.out.println(properties2);
}
}
其他(了解)
SortedMap 接口和 TreeMap 实现类
TreeMap 就是一个红黑树数据结构,每个 key-value 对就作为红黑树的一个节点。
TreeMap 存储 key-value 对(节点)时,需要根据 key 对节点进行排序,它能保证所有的 key-value 对
处于有序状态。
TreeMap 有两种排序方式:自然排序和自定义排序。
自然排序:TreeMap 的所有 key 都应该实现 Comparable 接口。
自定义排序:
TreeMap 中判断两个 key 是否相等:两个 key 通过 compareTo() 方法返回 0,它就认为这两个 key 就
是相等的。
class
WeakHashMap 实现类
它与 HashMap 用法几乎一样。
区别:HashMap 的 key 保留了对实际对象的强引用;WeakHashMap 的 key 只保留了对实际对象的弱
引用。
垃圾回收时数据会消失
IdentityHashMap 实现类
实现机制与 HashMap 基本一致,它在处理两个 key 相等时比较特殊,在 IdentityHashMap 中,只
有当两个 key 相等时(key1 == key2),才会认为两个 key 相等。
EnumMap 实现类
是一个与枚举类一起使用的 Map 实现,它所有的 key 都必须是单个枚举类的枚举值。创建 EnumMap
时,需要显示或隐式指定它对应的枚举类。