1.HashMap——底层是数组+链表,线程不安全(允许存放null键<只能一个null值键>和null值,当键为null时把对应值放在数组首位 )(HashMap有一个子类LinkedHashMap,可以根据存入顺序进行
HashMap采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体,Entry类实际上是一个单向的链表结构,它具有Next指针,可以连接下一个Entry实体,依次来解决Hash冲突的问题,因为HashMap是按照Key的hash值来计算Entry在HashMap中存储的位置的,如果hash值相同,而key内容不相等,那么就用链表来解决这种hash冲突。(用数组存储,当hash值冲突时就用链表依次连接<采用链表解决hash冲突>)
HashMap的存储
1. public V put(K key, V value) {
2. // HashMap允许存放null键和null值。
3. // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。
4. if (key == null)
5. return putForNullKey(value);
6. // 根据key的keyCode重新计算hash值。
7. int hash = hash(key.hashCode());
8. // 搜索指定hash值在对应table中的索引。
9. int i = indexFor(hash, table.length);
10. // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。
11. for (Entry<K,V> e = table[i]; e != null; e = e.next) {
12. Object k;
13. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
14. V oldValue = e.value;
15. e.value = value;
16. e.recordAccess(this);
17. return oldValue;
18. }
19. }
20. // 如果i索引处的Entry为null,表明此处还没有Entry。
21. modCount++;
22. // 将key、value添加到i索引处。
23. addEntry(hash, key, value, i);
24. return null;
25. }
- 先计算新加入键值对的hash值(第七行)
- 在根据hash值和数组长度取余,得到在数组中的一个索引(第九行)
- 如果这个位置有Entry,先查找这个Entry链表中有没有和给的键值对key相同的,如果有的话用新的value覆盖旧的value
- 最后将这个新的键值对放在这个链表的链头,链尾是最先加入的元素,如果数组该位置上没有元素就直接把这个元素放进去
(查找的时候也是同理,先通过计算key的hash值找到table的对应位置,然后在这个位置中挨个遍历找到与之相同的key)
-
put(K key, V value)——存值
-
putAll(Map map)——添加一个同类型Map
-
get(Object key)——根据键名取值
-
isEmpty()——判断是否为空
-
containsKey(Object key)——判断是否含有key
-
containsValue(Object value)——判断是否含有value
-
remove(Object key)——删除这个key值下的value
-
size()——Hashmap的元素个数
-
values()——返回存放value值的Collection集合
-
keySet()——返回存放key值的Set集合
-
entrySet()——返回包含映射关系的Set集合(就是把Key-Value作为一个一个整体存放到Set集合中去)------- 通过getKey()和getValue()方法获得键和值
—————————————————————————————————————————————————
四种遍历map的方式
Entry
由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。
Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value (我们总说键值对键值对, 每一个键值对也就是一个Entry)
Map.Entry里面包含getKey()和getValue()方法
Iterator<Map.Entry<Integer, Integer>> it=map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry<Integer,Integer> entry=it.next();
int key=entry.getKey();
int value=entry.getValue();
System.out.println(key+" "+value);
}
entrySet
entrySet是 java中 键-值 对的集合,Set里面的类型是Map.Entry,一般可以通过map.entrySet()得到。
entrySet实现了Set接口,里面存放的是键值对。一个K对应一个V。
用来遍历map的一种方法。
Set<Map.Entry<String, String>> entryseSet=map.entrySet();
for (Map.Entry<String, String> entry:entryseSet) {
System.out.println(entry.getKey()+","+entry.getValue());
}
即通过getKey()得到K,getValue得到V。
keySet
还有一种是keySet, keySet是键的集合,Set里面的类型即key的类型
Set<String> set = map.keySet();
for (String s:set) {
System.out.println(s+","+map.get(s));
}
—————————————————————————————————————————————————
(enteySet速度要比keySet速度快得多)
2.Hashtable——底层是数组+链表,线程安全(不允许key和value为null )
3.TreeMap——底层是红黑树,线程不安全(不允许key为null,允许value为null)
(Map的方法他都有)
-
public Map.Entry<K,V> ceilingEntry(K key)——返回指定的Key大于或等于的最小值的元素(返回的是Entry),如果没有,则返回null
-
public K ceilingKey(K key)—— 返回指定的Key大于或等于的最小值的Key(返回的是key的值),如果没有,则返回null
-
public Map.Entry<K,V> firstEntry()——返回集合最小key的元素(返回的是Entry)
-
public Map.Entry<K,V> lastEntry()——返回集合最大Key的元素(返回的是Entry)
-
public K firstKey()——返回集合中最小Key的key
-
public K lastKey()——返回集合中最大Key的key
3.1 TreeMap排序
实现排序的有两个接口Comparable和Comparator接口
-
Comparable:内部比较器,需要在类的内部重写compareTo方法
-
Comparator:外部比较器,无需改变类的结构,用于那些没有实现Comparable接口或者已经实现Comparable接口但是对排序规则不满意的,需要重新写一个比较器类,实现Comparator接口,重写compare方法
-
用this对象-参数对象,就是升序
-
用参数对象-this对象,就是降序
例子:
1.comparable
public class SortedTest implements Comparable<SortedTest> {
private int age;
public SortedTest(int age){
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//自定义对象,实现compareTo(T o)方法:
public int compareTo(SortedTest sortedTest) {
int num = this.age - sortedTest.getAge();
//为0时候,两者相同:
if(num==0){
return 0;
//大于0时,传入的参数小:
}else if(num>0){
return 1;
//小于0时,传入的参数大:
}else{
return -1;
}
}}
public class TreeMapTest {
public static void main(String[] agrs){
//自然顺序比较
naturalSort();
}
//自然排序顺序:
public static void naturalSort(){
//第一种情况:Integer对象
TreeMap<Integer,String> treeMapFirst = new TreeMap<Integer, String>();
treeMapFirst.put(1,"jiaboyan");
treeMapFirst.put(6,"jiaboyan");
treeMapFirst.put(3,"jiaboyan");
treeMapFirst.put(10,"jiaboyan");
treeMapFirst.put(7,"jiaboyan");
treeMapFirst.put(13,"jiaboyan");
System.out.println(treeMapFirst.toString());
//第二种情况:SortedTest对象
TreeMap<SortedTest,String> treeMapSecond = new TreeMap<SortedTest, String>();
treeMapSecond.put(new SortedTest(10),"jiaboyan");
treeMapSecond.put(new SortedTest(1),"jiaboyan");
treeMapSecond.put(new SortedTest(13),"jiaboyan");
treeMapSecond.put(new SortedTest(4),"jiaboyan");
treeMapSecond.put(new SortedTest(0),"jiaboyan");
treeMapSecond.put(new SortedTest(9),"jiaboyan");
System.out.println(treeMapSecond.toString());
}}
2.comparator
public class SortedTest {
private int age;
public SortedTest(int age){
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}}
public class SortedTestComparator implements Comparator<SortedTest> {
//自定义比较器:实现compare(T o1,T o2)方法:
public int compare(SortedTest sortedTest1, SortedTest sortedTest2) {
int num = sortedTest1.getAge() - sortedTest2.getAge();
if(num==0){//为0时候,两者相同:
return 0;
}else if(num>0){//大于0时,后面的参数小:
return 1;
}else{//小于0时,前面的参数小:
return -1;
}
}}
public class TreeMapTest {
public static void main(String[] agrs){
//自定义顺序比较
customSort();
}
//自定义排序顺序:
public static void customSort(){
TreeMap<SortedTest,String> treeMap = new TreeMap<SortedTest, String>(new SortedTestComparator());
treeMap.put(new SortedTest(10),"hello");
treeMap.put(new SortedTest(21),"my");
treeMap.put(new SortedTest(15),"name");
treeMap.put(new SortedTest(2),"is");
treeMap.put(new SortedTest(1),"jiaboyan");
treeMap.put(new SortedTest(7),"world");
System.out.println(treeMap.toString());
}}