因为前面讲hashMap的源码,发现太长了,所以本章作为补充,毕竟Map的接口下还有其他常用的实现类,所以本篇是讲LinkedHashMap还有TreeMap,以及Properties类。
LinkedHashMap
看名知其意,也是一个链表结构,而链表结构的原理前面说过,在讲解List接口中的时候已经说过,如果对于这个有点不了解可以看。java基础 浅解list集合中ArrayList与LinkedList
老规矩,先看代码,然后进行讲解(jdk1.8)。
public class LinkedHlashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
可以看出LinkedHashMap是HashMap中子类。看见这个,然后有些人想到之前的见过的继承中的重写,脑海中会补充一个方法,就是LinkedHlashMap中重写put方法,我们看源码。
在LinkedHashMap中源码中没有put方法,那用另一个方法然后新建一个LinkedHashMap然后调用put方法,通过ctrl+点击鼠标进入源码,如下:
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
但是仔细一看其还是HashMap源码中方法,这个时候就有一个一个疑问,到底是什么原因导致的,那样其他的方法是否被重写了,我们依次查看其中都没有重写。
但是找到这个
/**
* HashMap.Node subclass for normal LinkedHashMap entries.
*/
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
Entry<K,V> extends HashMap.Node<K,V>,可以看出在LinkedHashMap中的Entry 继承了HashMap node。以及重写了newNode 方法
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
// link at the end of list
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
可以看出LinkedHashMap是通过重写了继承HashMap中的内部类Node中的方法,将其变成一个链表结构的。变成了一个双向链表结构。所以其是有序的, 具体链表结构与数组结构的优缺点,前面list中讲解过,所以不再多说。
TreeMap
这个其实就是就是一个二叉树结构,前面也讲解过,但是其存储数据的话,如果存储自己创建的对象,需要两种方式,java基础 comparable与comparator的作用以及区别
其源码结构一般的时候不会有人具体问,所以暂时不再进行详解,如果需要后期补充。
其中记得其存储自己创建的类的两种方式,具体如何实现可以看前面的连结,那个里面讲解了。对于comparable不再过多解释,但是对于实现Comparator接口可能具体如何写可以看以下TreeMap构造方法
TreeMap(Comparator<? super K> comparator) 构造一个新的、空的树映射,该映射根据给定比较器进行排序。
Properties
对于Properties (类位于 java.util.Properties)在Java中很多时候是将其作为一个配置文件,进行使用的, 不过看其源码后发现
public class Properties extends Hashtable<Object,Object> {
也就明白为什么会在讲解map 的是将其进行一个补充,放在这篇文章里面。
对其主要就是使用即可,即在变成中遇见一些需要修改或者方便补充的变量,将其放在配置文件,让程序读取即可。
所以具体还是看代码创建一个test.propertiest 配置文件
date=2021-03-03
file=\test.txt
使用的properties文件的方法
public class test {
public static void main(String[] args) {
try {
Properties props = new Properties();
//如果用FileInputStream进行导入
// String f = "src/test/test.properties";
// props.load(new java.io.FileInputStream(f));
//如果用getResourceAsStream导入
String f = "test.properties";
props.load(new Father().getClass().getResourceAsStream(f));
//循环和map一样可以进行遍历,不过一般的时候不会这样用
Set<Entry<Object, Object>> ser=props.entrySet();
Iterator it=ser.iterator();
while(it.hasNext()) {
Entry<Object, Object> e=(Entry<Object, Object>) it.next();
System.out.println(e.getKey());
System.out.println(e.getValue());
}
//一般会直接调用某个值,然后得到要要的值
System.out.println(props.get("date"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
补充 set为map的key
在讲解map的时候,我们说的是set其实是map的key的值,所以我们看一下。
在new HashSet<>(); 可以看一下源码
/**
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*/
public HashSet() {
map = new HashMap<>();
}
看如何加入数据,其实可以看其add方法,然后我们可以观看其如何进行存储数据的的。
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
//由上面可以知道PRESENT没有什么意义,智商new 创建一个对象占住map中的value值
return map.put(e, PRESENT)==null;
}
最后发现还是调用的是map 中的put方法
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with <tt>key</tt>, or
* <tt>null</tt> if there was no mapping for <tt>key</tt>.
* (A <tt>null</tt> return can also indicate that the map
* previously associated <tt>null</tt> with <tt>key</tt>.)
*/
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
这个就需要再走一遍了,其实再讲解HashMap中的put方法。可以得知如果put的key值一样的话会重写讲key的value值重新赋值。所以set中不用存储两个相同的值。其实可以看出set的很多的方法其实调用的map中的方法。