1.Map
Map 是一种键-值对(key-value)集合,Map 集合中的每一个元素都包含一个键对象和一个值对象。其中,键对象不允许重复,而值对象可以重复,并且值对象还可以是 Map 类型的,就像数组中的元素还可以是数组一样。
Map集合的实现类:HashTable、LinkedHashMap、HashMap、TreeMap
Map Map 接口主要有两个实现类:HashMap 类和 TreeMap 类。其中,HashMap 类按哈希算法来存取键对象,而 TreeMap 类可以对键对象进行排序。
Map的特点:
- Map接口和Collection接口的不同
- Map是双列的,Collection是单列的
- Map的键唯一,Collection的子体系Set是唯一的
- Map集合的数据结构针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
方法:
方法 | 描述 |
---|---|
put(K key,V value) | 添加元素。如果键是第一次存储,就直接存储元素,返回null;如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值 |
clear() | 移除所有的键值对元素 |
remove(Object key) | 根据键删除键值对元素,并把值返回 |
containsKey(Object key) | 判断集合是否包含指定的键 |
containsValue(Object value) | 判断集合是否包含指定的值 |
isEmpty() | 判断集合是否为空 |
entrySet() | 返回一个键值对的Set集合 |
get(Object key) | 根据键获取值 |
keySet() | 获取集合中所有键的集合 |
values() | 获取集合中所有值的集合 |
size() | 返回集合中的键值对的对数 |
Map集合的遍历之键找值
获取所有键的集合
遍历键的集合,获取到每一个键
根据键找值
public class Test4 {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put("S10258741","张三");
map.put("S10258742","李四");
map.put("S10258743","王五");
map.put("S10258744","赵六");
Set<String> phones = map.keySet();
for (String next : phones) {
System.out.println("学号:"+next+" 姓名:"+map.get(next));
}
}
}
输出结果:
LinkedHashMap的概述和使用
概述: Map 接口的哈希表和链接列表实现,具有可预知的迭代顺序
特点: 底层的数据结构是链表和哈希表 元素有序 并且唯一元素的有序性由链表数据结构保证 唯一性由 哈希表数据结构保证Map集合的数据结构只和键有关
TreeMap集合
TreeMap 键不允许插入null
TreeMap: 可以保证键的排序和唯一性,排序分为自然排序和比较器排序,线程是不安全的效率比较高
TreeMap集合排序:实现Comparable接口,重写CompareTo方法
使用比较器
Map中的键唯一,但是当存储自定义对象时,需要重写Hashcode和equals方法
2.List
List接口是继承Collection接口,所以Collection集合中有的方法,List集合也继承过来。
方法:
方法 | 描述 |
---|---|
add(int index, E element) | 在指定位置插入元素,后面的元素都往后移一个元素。 |
addAll(int index, Collection<? extends E> c) | 在指定的位置中插入c集合全部的元素,如果集合发生改变,则返回true,否则返回false。 |
get(int index) | 返回list集合中指定索引位置的元素 |
indexOf(Object o) | 返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1 |
listIterator() | 返回此列表元素的列表迭代器(按适当顺序) |
listIterator(int index) | 从指定位置开始,返回此列表元素的列表迭代器(按适当顺序) |
remove(int index) | 删除指定索引的对象 |
set(int index, E element) | 在索引为index位置的元素更改为element元素 |
subList(int fromIndex, int toIndex) | 返回从索引fromIndex到toIndex的元素集合,包左不包右 |
listIterator和iterator的区别是什么呢?下面这篇博客比较详细的分析,可以参考。
https://blog.csdn.net/longshengguoji/article/details/41551491
这里大概讲一下他们的区别:
当只需要遍历集合时,两个迭代器的功能都是一样。
但是listIterator迭代器只能用于List和他的实现子类,iterator迭代器可以用于所有的集合使用。
所不同的就是listIterator迭代器的功能会比iterator迭代器的功能要。
listIterator迭代器可以在遍历集合时添加、修改和删除,而iterator迭代器在遍历集合时只有删除。
List接口的常用实现类有ArrayList和LinkedList:
通常情况下声明为List类型,实例化时根据实际情况的需要,实例化为ArrayList或LinkedList,例如:
List<String> l = new ArrayList<String>();// 利用ArrayList类实例化List集合
List<String> l2 = new LinkedList<String>();// 利用LinkedList类实例化List集合
ArrayList
ArrayList底层是用数组实现的,可以认为ArrayList是一个可改变大小的数组。随着越来越多的元素被添加到ArrayList中,其规模是动态增加的。
ArrayList遍历
public class Test {
public static void main(String[] args) {
List<String> lis = new ArrayList<>();
lis.add("S10258741");
lis.add("S10258742");
lis.add("S10258743");
lis.add("S10258744");
for(String li : lis){
System.out.println("li = " + li);
}
}
}
输出结果:
LinkedList
LinkedList底层是通过双向链表实现的。所以,LinkedList和ArrayList之前的区别主要就是数组和链表的区别。
所以,LinkedList和ArrayList相比,增删的速度较快。但是查询和修改值的速度较慢。同时,LinkedList还实现了Queue接口,所以他还提供了offer(), peek(), poll()等方法。
LinkedList遍历
public class Test {
public static void main(String[] args) {
List<String> lis = new LinkedList<String>();
lis.add("S10258741");
lis.add("S10258742");
lis.add("S10258743");
lis.add("S10258744");
for(String lkl : lis){
System.out.println("lkl = " + lkl);
}
}
}
输出结果:
如何选择
如果不涉及到多线程就从LinkedList、ArrayList中选。 LinkedList更适合从中间插入或者删除(链表的特性)。 ArrayList更适合检索和在末尾插入或删除(数组的特性)。
3.Set
特点:
不能存储相同的元素。
接口实现有HashSet和TreeSet
HashSet底层是用HashMap来实现的,将传入的值作为Map的键,从而不会重复
具有和List相同的方法
同时因为其是一个抽象的接口:所以不能直接实例化一个set对象。(Set s = new Set() )错误
方法
方法 | 描述 |
---|---|
begin() | 返回指向第一个元素的迭代器 |
end() | 返回指向最后一个元素的迭代器 |
count() | 返回某个值元素的个数 |
empty() | 判断集合是否为空,是则返回true |
clear() | 清除所有元素 |
insert() | 在集合中插入元素 |
erase() | 删除集合中的元素() |
size() | 集合中当前的元素个数 |
swap() | 交换两个集合变量 |
find() | 返回一个指向被查找到元素的迭代器 |
lower_bound() | 返回指向大于(或等于)某值的第一个元素的迭代器 |
upper_bound() | 返回大于某个值元素的迭代器 |
max_size() | 返回集合能容纳的元素的最大限值 |
value_comp() | 返回一个用于比较元素间的值的函数 |
rbegin() | 返回指向集合中最后一个元素的反向迭代器(返回的值和end()相同) |
rend() | 返回指向集合中第一个元素的反向迭代器(返回的值和rbegin()相同) |
key_comp() | 返回一个用于元素间值比较的函数 |
equal_range() | 返回集合中与给定值相等的上下限的两个迭代器 |
get_allocator() | 返回集合的分配器 |
HashSet
HashSet遍历
public class Test {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(5);
set.add(1);
set.add(6);
set.add(2);
set.add(4);
set.add(3);
for (Object object : set) {
System.out.println(object);
}
}
}
输出结果:
“不保证有序”和“保证无序”不等价,HashSet的iterator是前者而不是后者,所以在一次运行中看到有序的结果也是正常的,但不能依赖这个有序行为。况且HashSet并不关心key的“排序”,就算其iterator“有序”通常也是说“按元素插入顺序”(LinkedHashSet就支持插入顺序遍历)。题主在此看到的所谓“有序”纯粹是个巧合。
具体解释:
https://www.zhihu.com/question/28414001
TreeSet
TreeSet:能够对元素按照某种规则进行排序。
特点:去除重复(唯一),按自然顺序排序
排序有两种方式:
A:自然排序
B:比较器排序
通过观看TreeSet的add()方法,发现最终要看TreeMap的put()方法
遍历:
public class Test {
public static void main(String[] args) {
TreeSet<String> hs=new TreeSet<String>();
hs.add("fhskjfghlakfbbv");
hs.add("gjdghxgfb");
hs.add("gfndgxbnxngmhjf");
hs.add("hgjgchnchgn");
hs.add("gjdghxgfb");
hs.add("gfndgxbnxngmhjf");
hs.add("fdhsfbvz");
hs.add("fhskjfghlakfbbv");
for(String i:hs){
System.out.println(i);
}
}
}
输出结果: