第十四章 集合
集合:
·可以动态保存多个对象,使用比较方便
·提供了一系列方便的操作对象的方法,add、remove、set、get等
·使用集合添加,删除新元素的示意代码-简洁明了
//老韩解读
//1. 集合主要是两组(单列集合 , 双列集合)
//2. Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合
//3. Map 接口的实现子类 是双列集合,存放的 K-V
//4. 把老师梳理的两张图记住
List list = new ArrayList();
// add:添加单个元素
list.add("jack");
list.add(10);//list.add(new Integer(10))
list.add(true);
System.out.println("list=" + list);
// remove:删除指定元素
//list.remove(0);//删除第一个元素
list.remove(true);//指定删除某个元素
System.out.println("list=" + list);
// contains:查找元素是否存在
System.out.println(list.contains("jack"));//T
// size:获取元素个数
System.out.println(list.size());//2
// isEmpty:判断是否为空
System.out.println(list.isEmpty());//F
// clear:清空
list.clear();
System.out.println("list=" + list);
// addAll:添加多个元素
ArrayList list2 = new ArrayList();
list2.add("红楼梦");
list2.add("三国演义");
list.addAll(list2);
System.out.println("list=" + list);
// containsAll:查找多个元素是否都存在
System.out.println(list.containsAll(list2));//T
// removeAll:删除多个元素
list.add("聊斋");
list.removeAll(list2);
System.out.println("list=" + list);//[聊斋]
// 说明:以 ArrayList 实现类来演示.
14.1 Collection接口遍历元素方式
1-使用Iterator(迭代器)
·Iterator对象称为迭代器,主要用于遍历Collection集合中的元素
·所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
·Iterator的结构
·Iterator仅用于遍历集合,Iterator本身并不存放对象
·迭代器执行原理
Iterator iterator = col.iterator();//得到一个集合的迭代器
//hasNext();判断时候还有下一个元素
while(iterator.hasNext()){
//next作用1.下移 2将下移以后集合位置上的元素返回
//itit加回车快速生成此代码
System.out.print(iterator.next());
}
//使用如下增强for循环可实现相同功能,快捷键I+回车
for (Object o : col) {
System.out.println(o);
}
14.2 List 接口和常用方法
public class ListMethod {
public static void main(String[] args) {
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
//void add(int index, Object ele):在 index 位置插入 ele 元素
// 在 index = 1 的位置插入一个对象
list.add(1, "韩顺平");
System.out.println("list=" + list);//list=[张三丰, 韩顺平, 贾宝玉]
// boolean addAll(int index, Collection eles):从 index 位置开始将 eles中的所有元素添加进来
List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1, list2);
System.out.println("list=" + list);//list=[张三丰, jack, tom, 韩顺平, 贾宝玉]
// Object get(int index):获取指定 index 位置的元素
// 说过
// int indexOf(Object obj):返回 obj 在集合中首次出现的位置
System.out.println(list.indexOf("tom"));//2
// int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
list.add("韩顺平");
System.out.println("list=" + list);//list=[张三丰, jack, tom, 韩顺平, 贾宝玉, 韩顺平]
System.out.println(list.lastIndexOf("韩顺平"));//5
// Object remove(int index):移除指定 index 位置的元素,并返回此元素
list.remove(0);
System.out.println("list=" + list);//list=[jack, tom, 韩顺平, 贾宝玉, 韩顺平]
// Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
list.set(1, "玛丽");
System.out.println("list=" + list);//list=[jack, 玛丽, 韩顺平, 贾宝玉, 韩顺平]
// List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
// 注意返回的子集合 fromIndex <= subList < toIndex
List returnlist = list.subList(0, 2);
System.out.println("returnlist=" + returnlist);//returnlist=[jack, 玛丽]
}
}
List的三种遍历方式
1)方式一:使用iterator //itit加回车快速生成此代码
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println("obj=" + obj);
}
2)方式二:使用增强for//快捷键I+回车
for (Object o : col) {
System.out.println(o);
}
3)方式三:使用普通for
for (int i = 0; i < list.size(); i++) {
System.out.println("对象=" + list.get(i));
}
14.3 Vector的基本介绍
Vector和ArrayList的比较:
14.4 LinkedList底层介绍
LinkedList的全面说明
·LinkedList低层实现了双向链表和双端队列的特点
·可以添加任意元素(元素可以重复),包括null
·线程不安全,没有实现同步
public class LinkedList01 {
public static void main(String[] args) {
//模拟一个简单的双向链表
Node jack = new Node("jack");
Node java = new Node("java");
Node python = new Node("python");
//双向链表的形成
jack.next = java;
java.next = python;
python.pre = java;
java.pre = jack;
//头结点和尾结点
Node first = jack;
Node last = python;
//从头到尾遍历
while (true){
if (first == null){
break;
}
System.out.println(first);
first = first.next;
}
System.out.println("从尾到头遍历");
//从尾到头遍历
while(true){
if (last==null){
break;
}
System.out.println(last);
last = last.pre;
}
//双向链表添加数据
Node zhangfei = new Node("张飞");
//添加张飞
zhangfei.next = java.next;
java.next = zhangfei;
zhangfei.pre = python.pre;
python.pre = zhangfei;
System.out.println("添加过张飞后遍历");
first = jack;
//从头到尾遍历
while (true){
if (first == null){
break;
}
System.out.println(first);
first = first.next;
}
}
}
//定义一个 Node 类,Node 对象 表示双向链表的一个结点
class Node {
public Object item; //真正存放数据
public Node next; //指向后一个结点
public Node pre; //指向前一个结点
public Node(Object name) {
this.item = name;
}
public String toString() {
return "Node name=" + item;
}
}
14.5 Set接口和常用方法
· Set接口基本介绍
1.无序(添加和取出的顺序不一致),没有索引
2.不允许重复元素,所以最多包含一个null;
· Set接口的常用方法
和List接口一样,Set接口也是Collection的子接口,因此,常用方法和Collection接口一样
· Set接口的遍历方式
同Collection的遍历方式一样,因为Set接口是Collection接口的子接口
1.可以使用迭代器(iterator)
2.增强for
3.不能使用索引方式来获取(普通for循环)
· HashSet的全面说明
1.HashSet实现了Set接口
2.HashSet实际上是HashMap,看下源码:
public HashSet(){
map = new HashMap<>();
}
3.可以存放null,但是只能有一个null
4.HashSet不保证元素是有序的,取决于hash后,在确定索引结果(即,不保证存放元素的顺序和取出顺序一致)
5.不能有重复元素/对象,在前面Set接口使用已经讲过
HashSet的底层是HashMap,HaspMap底层是(数组+链表+红黑树)
HashSet的添加元素底层是如何实现的(hash()+equals())
14.6 Set 接口实现类- LinkedHashSet
LinkedHashSet的全面说明:
1.LinkedHashSet是HashSet的子类
2.LinkedHashSet底层是一个LinkedHashMap(HashMap的子类),底层维护了一个 数组+双向链表
3.LinkedHashSet根据元素的hashCode值决定元素的存储位置,同时使用链表维护元素的次序(图),这使得元素看以来是以插入顺序保存的
4.LinkedHashSet不允许添加重复元素
14.7 Map 接口和常用方法
JDK8的Map接口特点:
1.Map与Collection并列存在,用于保存具有映射关系的数据:Key-Value
2.Map中的Key和Value可以是任何引用类型的数据,会封装到HaspMap$Node对象中
3.Map中的key不允许重复,原因和HashSet一样
4.Map中的value可以重复
5.Map中的key可以为null,value也可以为null,注意key为null,只能有一个,value为null可以有多个
6.常用String类作为Map的key
7.key和value之间存在单向一对一关系,即通过key总能找到对应的value
//Map接口常用方法
public class MapMethod {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", new Book("", 100));//OK
map.put("邓超", "孙俪");//替换-> 一会分析源码
map.put("王宝强", "马蓉");//OK
map.put("宋喆", "马蓉");//OK
map.put("刘令博", null);//OK
map.put(null, "刘亦菲");//OK
map.put("鹿晗", "关晓彤");//OK
map.put("hsp", "hsp 的老婆");
System.out.println("map=" + map);
// remove:根据键删除映射关系
map.remove(null);
System.out.println("map=" + map);
// get:根据键获取值
Object val = map.get("鹿晗");
System.out.println("val=" + val);
// size:获取元素个数
System.out.println("k-v=" + map.size());
// isEmpty:判断个数是否为 0
System.out.println(map.isEmpty());//F
// clear:清除 k-v
map.clear();
System.out.println("map=" + map);//map={}
// containsKey:查找键是否存在
System.out.println("结果=" + map.containsKey("hsp"));//结果=false
}
}
class Book {
private String name;
private int num;
public Book(String name, int num) {
this.name = name;
this.num = num;
}
}
//Map遍历方式
1.containsKey:查找键是否存在
2.keySet:获取所有的键
3.entrySet:获取所有的关系k-v
4.value:获取所有的值
public class MapFor {
public static void main(String[] args) {
Map map = new HashMap();
map.put("邓超", "孙俪");
map.put("王宝强", "马蓉");
map.put("宋喆", "马蓉");
map.put("刘令博", null);
map.put(null, "刘亦菲");
map.put("鹿晗", "关晓彤");
//第一组: 先取出 所有的 Key , 通过 Key 取出对应的 Value
Set keyset = map.keySet();
//(1)增强for
System.out.println("第一组第一种方式");
for (Object key : keyset) {
System.out.println(key + "-" + map.get(key));
}
//(2)迭代器
System.out.println("第一组第二种方式");
Iterator iterator = keyset.iterator();
while (iterator.hasNext()) {
Object key = iterator.next();
System.out.println(key + "-" + map.get(key));
}
//第二组: 把所有的 values 取出
Collection values = map.values();
//这里可以使用所有的 Collections 使用的遍历方法
// (1) 增强 for
System.out.println("---取出所有的 value 增强 for----");
for (Object value : values) {
System.out.println(value);
}
//(2) 迭代器
System.out.println("---取出所有的 value 迭代器----");
Iterator iterator2 = values.iterator();
while (iterator2.hasNext()) {
Object value = iterator2.next();
System.out.println(value);
}
//第三组: 通过 EntrySet 来获取 k-v
Set entrySet = map.entrySet();// EntrySet<Map.Entry<K,V>>
// (1) 增强 for
System.out.println("----使用 EntrySet 的 for 增强(第 3 种)----");
for (Object entry : entrySet) {
//将 entry 转成 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
//(2) 迭代器
System.out.println("----使用 EntrySet 的 迭代器(第 4 种)----");
Iterator iterator3 = entrySet.iterator();
while (iterator3.hasNext()) {
Object entry = iterator3.next();
//System.out.println(next.getClass()); // HashMap$Node -实现-> Map.Entry (getKey,getValue)
// 向下转型 Map.Entry
Map.Entry m = (Map.Entry) entry;
System.out.println(m.getKey() + "-" + m.getValue());
}
}
}
14.8 Map 接口实现类-Hashtable
14.9Map 接口实现类-Properties
14.10 总结-开发中如何选择集合实现类(记住)
public class TreeSet_ {
public static void main(String[] args) {
//老韩解读
// 1. 当我们使用无参构造器,创建 TreeSet 时,仍然是无序的
// 2. 老师希望添加的元素,按照字符串大小来排序
// 3. 使用 TreeSet 提供的一个构造器,可以传入一个比较器(匿名内部类)
// 并指定排序规则
// 4. 简单看看源码
//
// 老韩解读
/*
1. 构造器把传入的比较器对象,赋给了 TreeSet 的底层的 TreeMap 的属性 this.comparator
public TreeMap(Comparator < ? super K > comparator) {
this.comparator = comparator;
}
2. 在 调用 treeSet.add("tom"), 在底层会执行到
if (cpr != null) {//cpr 就是我们的匿名内部类(对象)
do {
parent = t;
//动态绑定到我们的匿名内部类(对象)compare
cmp = cpr.compare(key, t.key);
if (cmp < 0) t = t.left;
else if (cmp > 0) t = t.right;
else //如果相等,即返回 0,这个 Key 就没有加入
return t.setValue(value);
} while (t != null);
}
*/
//TreeSet treeSet = new TreeSet();
TreeSet treeSet = new TreeSet(new Comparator() {
@Override
public int compare(Object o1, Object o2) {
// return ((String) o2).compareTo((String) o1);
return ((String) o1).length() - ((String) o2).length();
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("sp");
treeSet.add("a");
treeSet.add("tom");
//输出
System.out.println("TreeSet=" + treeSet);
}
}
14.11 Collections工具类
//Collections工具类介绍
1.Collections是一个操作Set、List和Map等集合的工具类;
2.Collections中提供了一系列静态的方法对集合元素进行排序、查找和修改等操作
//排序操作(均为static方法)
1.reverse(List):反转List中元素的顺序
2.shuffle(List):对List集合元素进行随机排序
3.sort(List):根据元素的自然排序对指定List集合元素按升序排序
4.sort(List,Comparator):根据指定Comparator产生的顺序对List集合元素进行排序。
5.swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换
6.max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
7.max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
8.//Object min(Collection) //Object min(Collection,Comparator) 参考 max 即可
9.//int frequency(Collection,Object):返回指定集合中指定元素的出现次数
10.//void copy(List dest,List src):将 src 中的内容复制到 dest 中
11.//boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值