java集合 collection & map
java集合 collection & map
Jin集合框架体系
Java 集合可分为 Collection 和 Map 两大体系
Collection 接口:用于存储一个一个的数据,也称单列数据集合
- List 子接口:用来存储有序的、可以重复的数据(主要用来替换数组,”动态”数组),实现类,
ArrayList
、LinkedList
、Vector
Set 子接口:用来存储无序的、不可重复的数据(类似于高中讲的 “集合”)
- 实现类:
HashSet
、LinkedHashSet
、TreeSet
Map 接口:用于存储具有映射关系 key-value 对的集合
- 实现类:
HashMap
、LinkedHashMap
、TreeMap
、Hashtable
、Properties
Collection 接口及方法
JDK 不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set 和 List)去实现
Collection 接口是 List 和 Set 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 集合
方法 | 描述 |
---|---|
add(E obj) | 添加元素对象到当前集合中 |
addAll(Collection other) | 添加 other 集合中的所有元素对象到当前集合中 |
int size() | 获取集合中实际存储的元素个数 |
Boolean isEmpty() | 判断当前集合是否为空 |
boolean contains(Object obj) | 判断当前集合中是否存在一个与 obj 对象 equals 返回 true 的元素 |
boolean containsAll(Collection coll) | 判断 coll 集合中的元素是否在当前集合中都存在。 即 coll 集合是否是当前集合的 “子集” |
boolean equals(Object obj) | 判断当 前集合与 obj 是否相等 |
void clear() | 清空集合元素 |
boolean remove(Object obj) | 从当前集合中删除第一个找到的与 obj 对象 equals 返回 true 的元素 |
boolean removeAll(Collection coll) | 从当前集合中删除所有与 coll 集合中相同的元素 |
boolean retainAll(Collection coll) | 从当前集合中删除两个集合中不同的元素,即当前集合中仅保留两个集合的交集 |
Object[] toArray() | 返回包含当前集合中所有元素的数组 |
hashCode() | 获取集合对象的哈希值 |
iterator(): | 返回迭代器对象,用于 集合遍历 |
举例:
@Test
public void TestCollection(){
//ArrayList 是 Collection 的子接口 List 的实现类之一
Collection list = new ArrayList();
// add()
list.add("aa");
list.add("bb");
list.add("cc");
// [aa, bb, cc]
System.out.println(list);
Collection list1 = new ArrayList();
list1.add("ff");
// addAll
list1.addAll(list);
// [ff, aa, bb, cc]
System.out.println(list1);
// int size() 4
System.out.println(list1.size());
// Boolean isEmpty()
Collection list2 = new ArrayList();
// arrayList2 为空 true
System.out.println(list2.isEmpty());
// boolean contains(Object obj)
// list2 包含 aa true
System.out.println(list1.contains("aa"));
// boolean containsAll(Collection coll)
// list1 都包含 list 的元素
System.out.println(list1.containsAll(list));
}
Iterator (迭代器)接口
用于遍历集合中的所有元素
Collection 接口继承了 java.lang.Iterable 接口,该接口有一个 iterator()方法,那么所有实现了 Collection 接口的集合类都有一个 iterator()方法,用以返回一个实现了 Iterator 接口的对象
Iterator 接口的常用方法:
- public E next(): 返回迭代的下一个元素
- public boolean hasNext(): 如果仍有元素可以迭代,则返回 true
举例:
@Test
public void IteratorTest(){
ArrayList list = new ArrayList();
list.add(11);
list.add(22);
list.add(33);
list.add(44);
list.add(55);
list.add(66);
// //获取迭代器对象
Iterator iterator = list.iterator();
while (iterator.hasNext()){ //判断是否还有元素可迭代
// 取出下一个元素
System.out.println(iterator.next());
}
}
foreach 循环
foreach 循环(也称增强 for 循环)是 JDK5.0 中定义的一个高级 for 循环,专门用来遍历数组和集合
格式:
for(元素的类型 局部变量: Collection 集合或数组 ){}
// 举例
List<Integer> nums = Arrays.asList(1, 2, 3);
for(Integer num : nums){
// 1 2 3
System.out.print(num);
}
List 接口
List 除了从 Collection 集合继承的方法外,List 集合里添加了一些根据索引来操作集合元素的方法
方法 | 描述 |
---|---|
void add(int index, Object ele) | 在 index 位置插入 ele 元素 |
boolean addAll(int index, Collection eles) | 从 index 位置开始将 eles 中的所有 元素添加进来 |
Object get(int index) | 获取指定 index 位置的元素 |
List subList(int fromIndex, int toIndex) | 返回从 fromIndex 到 toIndex 位置的子集合 |
int indexOf(Object obj) | 返回 obj 在集合中首次出现的位置 |
int lastIndexOf(Object obj) | 返回 obj 在当前集合中末次出现的位置 |
Object remove(int index) | 移除指定 index 位置的元素,并返回此元素 |
Object set(int index, Object ele) | 设置指定 index 位置的元素为 ele |
举例:
@Test
public void testList(){
ArrayList list = new ArrayList();
list.add(0);
list.add(1);
list.add(2);
// 向索引为1 的位置添加
list.add(1,6);
// [0, 6, 1, 2]
System.out.println(list);
// 删除索引为1的元素
list.remove(1);
// [0, 1, 2]
System.out.println(list);
// 获取索引为2的元素
System.out.println(list.get(2));
// 把索引为0的元素替换10
list.set(0, 10);
// [10, 1, 2]
System.out.println(list);
}
ArrayList
- ArrayList 是 list 接口的只要实现类
- ArrayList 是对象引用的一个 “变长” 数组
- Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 实例,也不是 Vector 实 例,即 Arrays.asList(…) 返回值是一个固定长度的 List 集合
LinkedList
对于频繁的插入或删除元素的操作,建议使用 LinkedList 类,效率较高
底层 采用链表(双向链表)结构存储数据
特有方法:
void addFirst(Object obj): 元素添加到头部
void addLast(Object obj):元素添加到尾部
Object getFirst() :获取头部元素
Object getLast() :获取尾部元素
Object removeFirst() :删除并返回第一个元素
Object removeLast():删除并返回最后一个元素
Vector
Vector 是一个古老的集合,JDK1.0 就有了。大多数操作与 ArrayList 相同,区别之处 在于 Vector 是线程安全的
构造方法:
// 创建一个默认的向量,默认大小为 10
Vector();
// 创建指定大小的向量
Vector(int size);
// 创建指定大小的向量,并且增量用 incr 指定
// 增量表示向量每次增加的元素数目
Vector(int size,int incr);
// 创建一个包含集合 c 元素的向量
Vector(Collection c);
特有方法:
- void addElement(Object obj) : 将指定的组件添加到此向量的末尾,将其大小增加 1
- void insertElementAt(Object obj,int index) :将指定对象作为此向量中的组件插入到指定的 index 处
- void setElementAt(Object obj,int index) :将此向量指定 index 处的组件设置为指定的对象
- void removeElement(Object obj):从此向量中移除变量的第一个(索引最小的)匹配项
- void removeAllElements():从此向量中移除全部组件,并将其大小设置为零
Set 接口
Set 接口相较于 Collection 接口没有提供额外的方法
Set 集合不允许包含相同的元素
HashSet
Set 主要实现类是 HashSet
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存储、查找、删除性 能
特点:1. 不能保证元素的排列顺序 2. HashSet 不是线程安全的 3. 集合元素可以是 null
HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法得到的 哈希值相等,并且两个对象的 equals()方法返回值为 true
对于存放在 Set 容器中的对象,对应的类一定要重写 hashCode()
和 equals(Object obj)
方法,以实现对象相等规则
HashSet 集合中元素的无序性,不等同于随机性。这里的无序性与元素的添加位置有关,具体的存储位置是由元素的 hashCode()调用后返回的 hash 值决定的
LinkeHashSet
LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表
维护元素的次序,这使得元素看起来是以添加顺序保存的
LinkedHashSet 插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很 好的性能
TreeSet
TreeSet 是 SortedSet 接口的实现类,TreeSet 可以按照添加的元素的指定的属性的 大小顺序进行遍历
TreeSet 底层使用红黑树
结构存储数据
TreeSet 特点:不允许重复、实现排序(自然排序或定制排序)
对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 或 compare(Object o1,Object o2)方法比较返回值,返回值为 0,则认为两个对象相等
map接口
map 是 集合框架用来存储这种映射关系的对象
Map 与 Collection 并列存在。用于保存具有映射关系的数据:key-value
Map 中的 key 和 value 都可以是任何引用类型的数据。但常用 String 类作为 Map 的 key
key-value 特点:
- Map 中的 key 用 Set 来存放,不允许重复,即同一个 Map 对象所对应的类,须重写 hashCode()和 equals()方法
- key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到唯一的、确定的 value,不同 key 对应的 value 可以重复。value 所在的类要重写 equals()方法
- key 和 value 构成一个 entry。所有的 entry 彼此之间是无序的、不可重复的
常用方法:
方法 | 描述 |
---|---|
Object put(Object key,Object value) | 将指定 key-value 添加到(或修改)当前 map 对象中 |
void putAll(Map m) | 将 m 中的所有 key-value 对存放到当前 map 中 |
Object remove(Object key) | 移除指定 key 的 key-value 对,并返回 value |
void clear() | 清空当前 map 中的所有数据 |
Object get(Object key) | 获取指定 key 对应的 value |
boolean containsKey(Object key) | 是否包含指定的 key |
boolean containsValue(Object value) | 是否包含指定的 value |
int size() | 返回 map 中 key-value 对的个数 |
boolean isEmpty() | 判断当前 map 是否为空 |
boolean equals(Object obj) | 判断当前 map 和参数对象 obj 是否相等 |
Set keySet() | 返回所有 key 构成的 Set 集合 |
Collection values() | 返回所有 value 构成的 Collection 集合 |
Set entrySet() | 返回所有 key-value 对构成的 Set 集合 |
举例:
@Test
public void testMap(){
// 创建 map 对象
HashMap map = new HashMap();
// put 添加元素
map.put("jay","可爱女人");
map.put("fantasy","开不了口");
map.put("叶惠美","晴天");
// {jay=可爱女人, fantasy=开不了口, 叶惠美=晴天}
System.out.println(map);
// Object remove(Object key) 删除指定的 key-value
map.remove("jay");
// {fantasy=开不了口, 叶惠美=晴天}
System.out.println(map);
// 查询指定 key 对应的 value "开不了口"
System.out.println(map.get("fantasy"));
// 获取所有的key
Set set = map.keySet();
// [fantasy, 叶惠美]
System.out.println(set);
// 获取所有 values
Collection values = map.values();
// [开不了口, 晴天]
System.out.println(values);
//所有的映射关系
Set entrySet = map.entrySet();
// [fantasy=开不了口, 叶惠美=晴天]
System.out.println(entrySet);
}
HashMap
特点:
- 是 Map 接口使用频率最高的实现类
- 线程不安全的。允许添加 null 键和 null 值
- 存储数据采用的哈希表结构,底层使用一维数组+单向链表+红黑树进行 key-value 数据的存储。与 HashSet 一样,元素的存取顺序不能保证一致
- 判断两个 key 相等的标准是:两个 key 的 hashCode 值相等,通过 equals() 方法返回 true
- 判断两个 value 相等的标准是:两个 value 通过 equals() 方法返回 true
练习:WordCount 统计
统计字符串中每个字符出现的次数
@Test
public void testWordCount() {
String str = "aaaabbbbbcccdddd";
char[] chars = str.toCharArray();
HashMap hashMap = new HashMap();
for (char c : chars) {
if (!hashMap.containsKey(c)) {
hashMap.put(c, 1);
} else {
hashMap.put(c, (int)(hashMap.get(c)) + 1);
}
}
// {a=4, b=5, c=3, d=4}
System.out.println(hashMap);
}
LinkedHashMap
特点:
LinkedHashMap 是 HashMap 的子类
存储数据采用的哈希表结构+链表结构,在 HashMap 存储结构的基础上,使用了一对 双向链表来记录添加元素的先后顺序,可以保证遍历元素时,与添加的顺序一致
通过哈希表结构可以保证键的唯一、不重复,需要键所在类重写 hashCode()方法、 equals()方法
TreeMap
特点:
TreeMap 存储 key-value 对时,需要根据 key-value 对进行排序。TreeMap 可以保 证所有的 key-value 对处于有序状态
TreeSet 底层使用红黑树结构存储数据
TreeMap 的 Key 的排序:
自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
定制排序:创建 TreeMap 时,构造器传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
TreeMap 判断两个 key 相等的标准:两个 key 通过 compareTo()方法或者 compare() 方法返回 0
Hashtable
特点:
Hashtable 是 Map 接口的古老实现类,JDK1.0 就提供了。不同于 HashMap, Hashtable 是线程安全的
Hashtable 实现原理和 HashMap 相同,功能相同。底层都使用哈希表结构(数组+单 向链表),查询速度快
与 HashMap 一样,Hashtable 也不能保证其中 Key-Value 对的顺序 • Hashtable 判断两个 key 相等、两个 value 相等的标准,与 HashMap 一致
与 HashMap 不同,Hashtable 不允许使用 null 作为 key 或 value
面试题:Hashtable 和 HashMap 的区别
HashMap: 底层是一个哈希表(jdk7:数组+链表;jdk8:数组+链表+红黑树), 是一个线 程不安全的集合,执行效率高
Hashtable: 底层也是一个哈希表(数组+链表), 是一个线程安全的集合,执行效率低 HashMap 集合 :可以存储 null 的键、null 的值
Hashtable 集合 ,不能存储 null 的键、null 的值
Hashtable 和 Vector 集合一样, 在 jdk1.2 版本之后被更先进的集合(HashMap,Arra yList)取代了。所以 HashMap 是 Map 的主要实现类,Hashtable 是 Map 的古老实现类
Hashtable 的子类 Properties(配置文件)依然活跃在历史舞台 Properties 集合是一个唯一和 IO 流相结合的集合
Properties
特点:
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
由于属性文件里的 key、value 都是字符串类型,所以 Properties 中要求 key 和 value 都是字符串类型
存取数据时,建议使用 setProperty(String key,String value)方法和 getProperty(String key)方法
Collections 工具类
Arrays,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) | 根据元素 自然 / Comparator 的顺序 ,返回给定集合中的最小元素 |
int binarySearch(List list,T key) | 在 List 集合中查找某个元素的下标, List 的元素必须是 T 或 T 的子类对象,是可比较大小的,集合也事先必须是有序 |
int binarySearch(List list,T key,Comparator c) | 同上,而且按照 c 比较器规则进行排序过的 |
void copy(List dest,List src) | 将 src 中的内容复制到 dest 中 |
boolean replaceAll(List list,Object oldVal,Object newVal) | 使用新值替换 List 对象 的所有旧值 |
unmodifiableXxx() | 返回指定 Xxx 的不可修改的视图 |
boolean addAll(Collection c,T… elements) | 将所有指定元素添加到指定 collection 中 |
synchronizedXxx() | 可使将指定集合包装成 线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题 |
举例:
@Test
public void testCollections(){
ArrayList<Object> list = new ArrayList<>();
// public static <T> boolean addAll(Collection<? super T> c,T...elements)
// 将所有指定元素添加到指定 collection 中。Collection 的集合的元素类型必须>=T 类型
Collections.addAll(list,"hello","java",1,2,3);
System.out.println(list); // [hello, java, 1, 2, 3]
// Object max(Collection)
List nums = Arrays.asList(5,8,1,2,7);
Object max = Collections.max(nums);
System.out.println(max); // 8
// reverse
Collections.reverse(nums);
System.out.println(nums); // [7, 2, 1, 8, 5]
// shuffle
List<String> arrList = Arrays.asList("java", "hello", "world");
Collections.shuffle(arrList);
System.out.println(arrList); // [hello, world, java]
// void copy(List dest,List src)
List src = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
// 将src中的内容复制到dest中 dest的空间大小不能小于src
List dest = Arrays.asList(new Object[src.size()]);
Collections.copy(dest,src);
// [1, 2, 3, 4, 5, 6, 7]
System.out.println(dest);
}
参考资料