目录
集合的框架体系
Java的集合类很多(背),主要分为两大类,如图:
一、Collection接口和常用方法
- Collection接口的特点
public interface Collection<E> extends Iterable<E>
- 有很多方法,是抽象,需要子类来实现..
- collection可以存放多个元素,每个元素可以是Object
- 有些Collection的实现类,可以存放重复的元素,有些不可以
- 有些Collection的实现类,有序(List:有序 可重复),无序(set:无序 不可重复)
- Collection接口没有直接的实现子类,通过它的子接口Set 和 List 来实现Collection即可
- Collection接口常用方法
- add:添加单个元素
- remove:删除指定元素
- contains:查找元素是否存在
- size:获取元素个数
- isEmpty:判断是否为空
- clear:清空
- addAll:添加多个元素
- containsAll:查找多个元素是否都存在
- removeAll:删除多个元素
- 说明:以ArrayList实现类来演示.
- 代码演示
package com.atguigu.collections;
import java.util.ArrayList;
import java.util.List;
public class CollectionCommonMethods {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
// TODO Auto-generated method stub
//1. 以 实现子类 ArrayList
//2. List 是 Collection 子接口
//3.
List list = new ArrayList();
//走方法
/*
* add:添加单个元素 (只要Object 对象,都可以放)
remove:删除指定元素
contains:查找元素是否存在
size:获取元素个数
isEmpty:判断是否为空
clear:清空
addAll:添加多个元素
containsAll:查找多个元素是否都存在
removeAll:删除多个元素
说明:以ArrayList实现类来演示.
*/
//可以随意
list.add("tom");
list.add("jack");
list.add("king");
list.add("smith");
list.add("scott");
//删除
list.remove(0);//删除第一个元素
list.remove("smith");//指定对象
List list2 = new ArrayList(); // list2= ["king", "jack"]
list2.add("king");
list2.add("jack");
list.removeAll(list2);
//contains
System.out.println(list.contains("scott"));//1
//size:获取元素个数
System.out.println(list.size());//1
//isEmpty:判断是否为空
System.out.println(list.isEmpty());// false
//clear:清空 , 所有的元素 全部拿掉
list.clear();
//addAll:添加多个元素
List list3 = new ArrayList(); // list2= ["king", "jack"]
list3.add("king~");
list3.add("jack~");
list.addAll(list3);
//removeAll:删除多个元素
list.removeAll(list3); //表示将 list集合中含有的 list3的元素删除
list.add("hello");
list.add("hello");
//输出
//小结
//1. 如果我们希望看到某个对象的真正执行的方法
//2. 最好使用debug 去看,因为我们只看继承关系,很难看到这个方法
// 到底是在哪个父类实现,或者重写
System.out.println("list=" + list.toString());
}
}
- Collection接口遍历元素方式1-使用Iterator(迭代器)
- 基本介绍
- Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。
- 所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象, 即可以返回一个迭代器。
- Iterator 的结构.
- Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
- 迭代器的执行原理
Iterator iterator = coll.iterator(); //得到一个集合的迭代器
//hasNext():判断是否还有下一个元素
while(iterator.hasNext()){
//next():①指针下移 ②将下移以后集合位置上的元素返回
System.out.println(iterator.next());
}
-
Iterator接口的方法
注意:在调用it.next()方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。
-
Collection接口遍历对象方式2-for循环增强
jdk5.0出现了增强for循环,可以代替iterator迭代器,特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或数组。
基本语法
for(元素类型 元素名 : 集合名或数组名) {
访问元素
}
1.1 List接口和常用方法
-
List接口基本介绍
- List 接口是 Collection 接口的子接口
- List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
- List集合中的每个元素都有其对应的顺序索引,即支持索引。
- List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
- JDK API中List接口的实现类有:
* List 集合里添加了一些根据索引来操作集合元素的方法
void add(int index, Object ele):在index位置插入ele元素
boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
Object get(int index):获取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出现的位置
int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
Object remove(int index):移除指定index位置的元素,并返回此元素
Object set(int index, Object ele):设置指定index位置的元素为ele , 相当于是替换.
List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
- List的三种遍历方式 [ArrayList, LinkedList]
方式一:使用iterator
Iterator iter = col.iterator();
while(iter.hasNext()){
Object o = iter.next();
}
方式二:使用增强for
for(Object o:col){
}
方式三:使用普通for
for(int i=0;i<list.size();i++){
Object object = list.get(i);
System.out.println(object);
}
1.1.1 ArrayList底层结构和源码分析
- ArrayList的全面说明
- ArrayList实现了List的接口,底层是一个数组,并实现可变的功能
ArrayList 属性 : transient Object[] elementData; - ArrayList实现了List所有的操作
- ArrayList 可以加入null,并且多个
- ArrayList 是由数组来实现数据存储的
- ArrayList 基本等同于Vector , , ArrayList是线程不安全,但是执行效率高
-
ArrayList的底层操作机制源码分析
- ArrayList中维护了一个Object类型的数组elementData. [debug 看源码]
transient Object[] elementData; - 当创建对象时,如果使用的是无参构造器,则初始elementData容量为0
- 当添加元素时:先判断是否需要扩容,如果需要扩容,则调用grow方法,否则直接添加元素到合适位置
- 如果使用的是无参构造器,如果第一次添加,需要扩容的话,则扩容elementData为10,如果需要再次扩容的话,则扩容elementData为1.5倍。
- 如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity
- 如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍。
1.1.2 Vector底层结构
- Vector类的全面说明
- [Vector底层也是一个可变对象数组] protected Object[] elementData;
- Vector 是线程同步的,即线程安全, Vector类的操作方法带有synchronized
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
在开发中,主要使用ArrayList ,只有在确实需要线程同步安全时,才使用Vector 增删改查和ArrayList一样
- Vector和ArrayList的比较【记住】
1.1.3 LinkedList底层结构
- LinkedList的全面说明
- LinkedList实现了双向链表和双端队列特点
- 实现了List接口的所有操作
- 可以添加任意元素(元素可以重复),包括null
- 线程不安全,没有实现同步
- LinkedList的底层操作机制
- LinkedList底层维护了一个双向链表.
- LinkedList中维护了两个属性first和last分别指向 首节点和尾节点
- 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.
- 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
- ArrayList 和 LinkedList比较
- 如何选择ArrayList和LinkedList:
- 如果我们改查的操作多,选择ArrayList
- 如果我们增删的操作多,选择LinkedList
- 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
- 在一个项目中,根据业务(JavaEE项目, 会说)灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList.
1.2 Set接口和常用方法
- Set接口基本介绍
- 无序(添加和取出的顺序不一致),没有索引[后面演示]
- 不允许重复元素,所以最多包含一个null
- JDK API中Set接口的实现类有:
- Set接口的常用方法
和List接口一样, Set接口也是Collection接口的子接口,因此,常用方法和Collection接口一样,没有多出其他的方式.
- Set接口的遍历方式
同Collection的遍历方式,因为Set接口是Collection接口的子接口。
1. 可以使用迭代器, 2. 增强for 3. 不能使用索引的方式来获取.
//1. 为啥 相同的元素,就加入不了?
// 答:因为他底层会使用 equals, 判断是否已经有这个元素.
//2. 为啥,加入顺序和取出的顺序不一样,但是每次取出的顺序是固定?
// 答: 因为hash算法后,这个元素不一定就是按照下标来增长,
1.2.1 Set接口实现类-HashSet
- HashSet的全面说明
- HashSet实现了Set接口
- HashSet实际上是HashMap
- 可以存放null值,但是只能有一个null
- HashSet不保证元素是有序的,取决于hash后,在进行取索引的结果
- 不能有重复元素. 在前面Set 接口使用已经讲过
- HashSet底层机制说明
分析HashSet的添加元素底层是如何实现
二、Map接口和常用方法
- Map接口的特点
- Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value
- Map 中的 key 和 value 都可以是任何引用类型的数据
- Map 中的 key 用Set来存放,不允许重复.(key不能重复)
- Map 中的 value 可以重复。
- Map 的key 可以为 null, value 也可以为null
- 常用String类作为Map的“键”
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value
- Map元素是无序的,因为key是用Set来存放的。而Set 本身是无序的.
- Map体系的继承图
- Map接口常用方法
- put:添加
- remove:根据键删除映射关系
- get:根据键获取值
- size:获取元素个数
- isEmpty:判断个数是否为0
- clear:清除
- containsKey:查找键是否存在
- Map接口遍历方法
- containsKey:查找键是否存在
- keySet:获取所有的键
- entrySet:获取所有关系
- values:获取所有的值
- 代码演示
//遍历方式1-》 迭代器
Set keySet = map.keySet();//获取 map 的 key Set
Iterator iterator = keySet.iterator(); // 获取到 Set 的 迭代器
while(iterator.hasNext()) {
Object key = iterator.next();
Object val = map.get(key);
System.out.println(key + "-" + val);
}
//第二种方式
System.out.println("=======第二种方式=======");
for(Object key : keySet) {//增强for 取出key
Object val = map.get(key);
System.out.println(key + "-" + val);
}
//第三种 entry, 表示一对键值对
//1. 得到entrySet, 即得到所有的 键值对
//增强for
System.out.println("第三种 entry");
Set entrys = map.entrySet(); //key-value
for (Object entry : entrys) { // entry 就是 key-val 类型就是 Entry
Map.Entry<Object, Object> v = (Entry) entry;//向下转型
Object key = v.getKey(); //通过 v 获取 key
Object val = v.getValue();//通过 v 获取 val
System.out.println(key + "-" + val); //
}
//迭代器取 [推荐使用]
System.out.println("=====迭代器取===========");
Iterator iterator2 = entrys.iterator();
while(iterator2.hasNext()) {
Map.Entry entry = (Map.Entry)iterator2.next(); //next 就是一个 Map.Entry
System.out.println(entry.getKey()+"-"+entry.getValue());
2.1 HashMap的基本使用和案例说明
- Map接口的常用实现类:HashMap、TreeMap和Properties。
- HashMap是 Map 接口使用频率最高的实现类。
- HashMap 是以 key-val 对的方式来存储数据 [案例]
- key 不能重复,但是是值可以重复,允许使用null键和null值。
- 如果添加相同的key , 则会覆盖原来的key-val ,等同于修改.(key不会替换,val会替换)
- 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.
- HashMap没有实现同步,因此是线程不安全的
- HashMap底层机制说明
2.2 Map接口实现类-Hashtable
- HashTable的基本介绍
- This class implements a hash table[该类实现hashtable]
- which maps keys to values [元素是键值对]
- Any non-null object can be used as a key or as a value [hashtable的键和值都不能为null]
- 所以是从上面看,hashTable 基本上和hashMap一样的.
- hashTable 是线程安全的,hashMap 是线程不安全的.
三、总结-开发中如何选择集合实现类(要求记住)
四、Collections工具类
- Collections工具类介绍
- Collections 是一个操作 Set、List 和 Map 等集合的工具类
- Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
- 排序操作:(均为static方法)
- reverse(List):反转 List 中元素的顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
- swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
- Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
//准备工作.
List list = new ArrayList();
list.add("john");
list.add("john");
list.add("lucy");
list.add("jack");
list.add("john3");
System.out.println("list=" + list);
//reverse(List):反转 List 中元素的顺序
Collections.reverse( list);
System.out.println("list=" + list);
// shuffle(List):对 List 集合元素进行随机排序
Collections.shuffle(list);
System.out.println("shuffle=" + list);
// sort::对 List 集合元素进行自然排序或定制排序
// 安装 码值来一个一个的比较,小的在前, 大的在后
Collections.sort(list);//默认升序
//从大到小
//可以进行扩展到其它类型
Collections.sort(list, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
// TODO Auto-generated method stub
if(!(o1 instanceof String) || !(o2 instanceof String)) {
return 0;
}
//将 类型转换
String s1 = (String)o1;
String s2 = (String)o2;
return s2.compareTo(s1); //从大到小
}
});
//测试:swap:交换集合中指定索引处的两个元素
//交换
Collections.swap(list, 1, 3);
//int frequency(Collection,Object):返回指定集合中指定元素的出现次数
int frequency = Collections.frequency(list, "john");
//void copy(List dest,List src):将src中的内容复制到dest中
List dest = new ArrayList(); //创建了一个dest List, 大小为10
for (int i = 0; i < list.size(); i++) {//使用list.size ,保证刚好
dest.add(i);
}
//吧list 中的元素拷贝给 dest
Collections.copy(dest , list);
System.out.println("dest的元素如下:");
//替换
Collections.replaceAll(list, "john", "tom.汉克斯");//阿甘
//max
//min
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
//可以定制
// Collections.min(list, new Comparator() {
//
// @Override
// public int compare(Object o1, Object o2) {
// // TODO Auto-generated method stub
// return 0;