目录
一、HashTable
HashTable是一个继承自Dictionary类的类,它实现了Map接口。HashTable的主要结构是一个Entry数组。
HashMap和HashTable的区别如下:
1. 线程安全性:HashMap是非线程安全的,在多线程环境下可能会出现线程安全问题;而HashTable是线程安全的,大部分方法使用synchronized关键字来确保线程同步,但性能较HashMap低。
2. 允许null值:HashMap的key可以为null(最多一个),value可以为null;HashTable则不允许key和value为null的元素。
3. 继承关系:HashMap继承自AbstractMap,HashTable继承自Dictionary抽象类,两者都实现了Map接口。
4. 初始容量:HashMap的初始容量为16,HashTable的初始容量为11。
5. 扩容机制:HashMap的扩容为原来的两倍,HashTable的扩容为两倍+1。
6. 红黑树转换:HashTable不会转换为红黑树。
另外个作者的部分源码说明HashTable底层实现-CSDN博客
二、Properties介绍
1.Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存数据。
2.他的使用特点和Hashtable类似
3.Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象并进行读取和修改
4.工作后xxx.properties文件通常作为配置文件,配合IO使用
https://www.cnblogs.com/xudong-bupt/p/3758136.html
三、TreeMap
TreeMap的底层还是维护的是红黑树,与HashMap不同的是每一个节点是Entry类型。
一般使用TreeMap要自己指定规定的比较器
直接上示例:
1.示例代码
public class TreeMapType {
public static void main(String[] args) {
TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() {
//通过匿名内部类的方法实现Comparator定义比较规则
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
treeMap.put("java", "a");
treeMap.put("apple", "b");
treeMap.put("orange", "c");
treeMap.put("php", "d");
treeMap.put("jsp", "e");//没有加入,因为通过比较器比较长度相同
System.out.println(treeMap);
}
}
输出结果
2.源码说明
添加元素的主要方法
/**
* 将指定的值与该映射中的指定键关联。如果映射中之前已存在此键的映射关系,
* 则替换旧值。
*
* @param key 要将指定值与之关联的键
* @param value 要与指定键关联的值
*
* @return 此键前一个关联的值,或 null(如果不存在此键的映射)。
* (null 返回也可以表示映射之前将 null 与 key 关联)
* @throws ClassCastException 如果指定的键无法与映射中当前的键进行比较
* @throws NullPointerException 如果指定的键为 null,且此映射使用自然排序,
* 或其比较器不允许 null 键
*/
public V put(K key, V value) {
// 获取根节点
Entry<K,V> t = root;
// 如果树为空,初始化根节点
if (t == null) {
// 检查类型(可能还有 null 值)
compare(key, key);
// 创建新的根节点并设置大小和修改计数
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null; // 返回 null,因为没有旧值可以替换
}
int cmp;
Entry<K,V> parent;
//以后添加数据
// 根据是否有比较器来区分处理路径
Comparator<? super K> cpr = comparator;
if (cpr != null) {
// 使用比较器搜索插入位置
do {//遍历所有的key,给当前key找到适当位置
parent = t;
cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类的compare
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else//如果遍历过程中,发现准备添加Key和当前已有的Key相等,就不添加
return t.setValue(value); // 如果找到键,则替换值并返回旧值
} while (t != null);
}
else {
// 如果键为 null,抛出异常,因为此映射不接受 null 键
if (key == null)
throw new NullPointerException();
// 使用键的自然顺序进行比较
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value); // 如果找到键,则替换值并返回旧值
} while (t != null);
}
// 创建新节点并确定其插入位置
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
// 插入后维护红黑树规则
fixAfterInsertion(e);
size++;
modCount++;
return null; // 返回 null,因为没有旧值可以替换
}
(1)构造器
传入的实现了Comparator接口的匿名内部类(对象),传给给TreeMap的comparator属性
(2)添加第一个数据
第一次添加,把k-v封装到Entry对象,放入root
(3)以后添加数据
(4)最后一个数据jsp添加失败
在循环中遍历到长度相同的数据php,插入失败
因为比较器比较的就只有长度。
将旧值覆盖 d ——>e