中午好朋友们。吃撑炸鸡的小柳开始脑子发懵低效学习啦。
首先呢为了助于理解Java库中的具体集合,先简要阐述一下集合之间的功能和关系。
- ArrayList 一种可以动态增长和缩减的索引序列
- LinkedList 一种可以在任何位置进行高效插入和删除操作的有序序列
- ArrayQeque 一种用循环数组实现的双端队列
- HashSet 一种没有重复元素的无序集合
- TreeSet 一种有序集
- EnumSet 一种包含枚举类型值的集
- LinkedHasSet 一种可以记住元素插入次序的集
- PriorityQuequ 一种允许搞笑删除最小元素的集合
- HashMap 一种存储键/值关联的数据结构
- TreeMap 一种键值有序排列的映射表
- EnumMap 一种键值属于枚举类型的映射表
- LinkedHashMap 一种可以记住键/值项添加次序的映射表
- WeakHashMap 一种其值无用武之地后可以被垃圾回收站回收的映射
- IdentityHashMap 一种用==而不是equals比较键值的映射表
(可对照下图理解记忆。)
集合框架中的类图
- 散列集
数组和链表可以按照大家的意愿排列元素的顺序。但当你不确定具体位置时就要逐个查询,消耗很多时间。
所以,如果不在意元素的顺序,有几种能够快速查找的数据结构。比如散列集。
这是一种众所周知的快速查询数据结构。它根据每个对象的实例域,使用hashCode()方法计算出一个独特的整数,称为散列码。
如果你的对象属于一个自定义类,那么需要额外实现这个类的hashCode()方法。【注:自己实现的hashCode()方法要与equals()方法兼容。即:a.equals(b)==true,则a,b必须有相同的散列码。】
(噢剩下的不想写了因为我有点懂了 走 下一题!)
- 树集
TreeSet类和散列集十分类似,不过它有改进,成为了一个有序集合。元素在被任意add()之后,树集会自动对它进行排布,送它去该去的位置。
例:
SortedSet<String> sorter=new TreeSet<>();//TreeSet implements SortedSet
sorter.add("Bob");
sorter.add("Amy");
sorter.add("Clerk");
for(String s:sorter) System.out.println(s);
结果将输出:Amy Bob Clerk
但是树集添加新元素的速度显然要比散列集慢。但比数组和链表还是要快很多的啦。
如果书中包含n个元素,那么按照树的特性,查找新元素的正确位置平均需要log2n(2是下标)次比较。
因为树集具比较功能,所以这些元素必须实现Comparable接口,或者构造集时必须提供一个Comparator。
- 优先级队列
这个队列厉害了。给大家上一个示例程序先,就懂了。
public class PriorityQueueTest{
public static void main(String[] args) {
PriorityQueue<LocalDate> qp=new PriorityQueue<LocalDate>();
qp.add(LocalDate.of(1906,12,9));
qp.add(LocalDate.of(1815,12,10));
qp.add(LocalDate.of(1903,12,3));
qp.add(LocalDate.of(1910,6,22));
System.out.println("Iterating over elements...");
for (LocalDate date:qp
) {
System.out.println(date);
}
System.out.println("Removing elements...");
while(!qp.isEmpty())
System.out.println(qp.remove());
}
}
注:程序先实现常规输出 再实现一边remove一边输出remove的返回值。
输出如下:
很容易看出,插入是无序随意的,但remove时每次都会将优先级最低的,最小的元素删除。
- 映射
如果每次要查询某一数据结构里的元素,都要精确知道元素值才能查找的话未免太不近人情。通常,我们只知道某些键的信息,想要找与它相对应的值。
映射(map),这种数据结构应运而生。
映射用来存放键/值对。提供了键,就能找到值。
1.基本映射操作
Java类库为映射提供了两个通用的实现:HashMap和TreeMap。这两个类都实现了Map接口。关于接口的详细信息参考Java|| 集合基础知识随笔(一)
HashMap对键进行散列。TreeMap用键的整体顺序对元素进行排列,形成一整棵搜索树。
由此可见,Map是对键起作用的,它操作键而不是值。
键必须是唯一的,不能对一个键同时存放两个值。
如果对一个键两次调用put()方法,第二个值就会取代第一个值,同时返回上一个值。
想检索一个对象:
String id="987-93-3332";
e=staff.get(id);
注:如果映射中没有给定键对应的值,get()返回null。
返回null值有时并不方便,所以可以给定一个替代null的默认值,getOrDefault()方法:
Map<String,Integer> scores=...;
int score=scores.getOrDefault(id,0);
最后遍历键值对最容易的方法是使用forEach方法+lambda表达式:
scores.forEach((k,v)->
System.out.println("key="+k,",value="+v));
好der,不说空话,一个例子给到大家。
public class MapTest {
public static void main(String[] args) {
Map<String,Employee> staff=new HashMap<>();
staff.put("144-25-5464", new Employee("Amy Lee"));
staff.put("567-24-2546", new Employee("Harry Hacker"));
staff.put("157-62-7935", new Employee("Gary Cooper"));
staff.put("456-62-5527", new Employee("Francesca Cruz"));
//打印所有成员
System.out.println(staff);
//删除某一成员
staff.remove("567-24-2546");
//替代一个成员
staff.put("456-62-5527", new Employee("Francesca Miller"));
//查看一个成员
System.out.println(staff.get("157-62-7935"));
//遍历映射
staff.forEach((k,v)->System.out.println("key="+k+",value="+v));
}
}
class Employee {
public String name;
public Employee(String name) {
this.name = name;
}
public String toString() {
return "[name=" + name + "]";
}
}
输出:
2.更新映射项
这里介绍一个merge()方法,非常好用。
merge() 适用于两种情况。
(1)给定的Key值不存在,它当作put(key, value)使用。
(2)key存在,remappingFunction 可以操作合并,大体来讲有四种情况可供选择(当然你想使用其他操作 sure 可以):
只需返回新值覆盖旧值: (old, new) -> new
只需返回旧值保留旧值: (old, new) -> old
以某种方式合并两者,例如: (old, new) -> old + new
甚至删除旧值: (old, new) -> null
例1:(完整例子可借鉴这位作者大大:merge()的使用,这里只写了merge方法的格式。我觉得不需要看例子,知道方法格式会用就OK)
operations.forEach(op ->
balances.merge(op.getAccNo(), op.getAmount(), BigDecimal::add)
);
例2:
counts.merge(word,1,Integer::sum);
例3:
result.merge(tag, 1, (a, b) -> a + b);
3.映射视图
映射视图有3种:
键集,值集合(不是一个集),键/值对集。
(啊我懒了 下面截图 应该讲的很明白没什么需要额外总结的了。)
好嘞!溜了!
朋友们下篇见!