// 负载因子 = 负载系数
private float loadFactor;
//修改的次数
private transient int modCount = 0;
复制代码
构造器
/**
主要还是调用了这个构造
initialCapacity : 数据容量
loadFactor : 负载因子
*/
public Hashtable(int initialCapacity, float loadFactor) {
if (initialCapacity < 0) // 判断初始的容量是否小于0
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
if (loadFactor <= 0 || Float.isNaN(loadFactor))// 判断负载因子是否小于等于0和传递的参数值是否合法
throw new IllegalArgumentException("Illegal Load: "+loadFactor);
if (initialCapacity==0) // 数据容量是否等等于0
initialCapacity = 1; // 如果是赋值为1
this.loadFactor = loadFactor; // 负载因子
table = new Entry<?,?>[initialCapacity]; // 初始数组table的容量大小
// threshold = 容量大小 * (负载系数 = 负载因子)
threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
}
// 自定义数组容量的构造
public Hashtable(int initialCapacity) {
this(initialCapacity, 0.75f);
}
// 无参构造
public Hashtable() {
this(11, 0.75f); // 它调用了一个有参构造
}
// 将另一个map集合的数据放入到Hashtable集合中
public Hashtable(Map<? extends K, ? extends V> t) {
this(Math.max(2*t.size(), 11), 0.75f);
putAll(t); // 这个方法做的事情就是遍历t集合的数据、调用Hashtable的put方法进行添加数据
}
复制代码
对集合CRUD简单说明
增
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) { // value 不能为null 否者抛出异常
throw new NullPointerException();
}
// 将构造中已经初始化的赋值给tab
Entry<?,?> tab[] = table;
// 计算hash值
int hash = key.hashCode();
// 计算下标
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings(“unchecked”)
// 找到该下标中的节点链表
Entry<K,V> entry = (Entry<K,V>)tab[index];
// 遍历该链表下的节点
for(; entry != null ; entry = entry.next) {
// 判断hash值是否相同等、内容是否相等
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value; // 将旧的value值赋值给old
entry.value = value; // 将新的value值赋值给旧的value值
return old; // 将旧的value值返回
}
}
// 如果链表没有重复的则进行添加在其他位置上
addEntry(hash, key, value, index); // 后面来说这个方法
return null;
}
复制代码
问题:
获取Hash值 :int hash = key.hashCode();
- 通过执行key对应类型实现的hashCode()方法获取对应的Hash值、没有实现则调用object类中的hashCode()来获取hash值、但是不能为null值会报空指针异常
获取下标:int index = (hash & 0x7FFFFFFF) % tab.length;
- 通过hash去取得一个下标
0x7FFFFFFF
表示int类型最大的数2147483647
、hash值按位与0x7FFFFFFF的结果取余tab数组的长度。
删
public synchronized V remove(Object key) {
Entry<?,?> tab[] = table; // 得到元素数组
int hash = key.hashCode(); // 算出Hash值
int index = (hash & 0x7FFFFFFF) % tab.length; // 算出下表
@SuppressWarnings(“unchecked”) // 抑制警告
// 获取改下标中的链表
Entry<K,V> e = (Entry<K,V>)tab[index];
for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {
// 如果hash只相同、并且内容相同
if ((e.hash == hash) && e.key.equals(key)) {
modCount++;// 操作数++
if (prev != null) { // 如果遍历到链表有上一个节点的情况下成立
prev.next = e.next;
} else {
tab[index] = e.next; // 将下一个节点的数据给数组
}
count–; // 内容数量–
V oldValue = e.value; // 将下一个节点赋值、作为返回出去
e.value = null; //将null赋值给下一个节点
return oldValue; // 返回被移除的元素
}
}
return null; // 没有则返回null
}
复制代码
改
改和增加是一样的他也是、通过key的hash值来找到对应位置、将其对应值覆盖
查
public synchronized V get(Object key) {
Entry<?,?> tab[] = table; // 得到元素数组
int hash = key.hashCode(); // 算出Hash值
int index = (hash & 0x7FFFFFFF) % tab.length; // 算出下表
// 遍历链表
for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
if ((e.hash == hash) && e.key.equals(key)) { // hash 相同值相同成立
return (V)e.value; // 得到key对应的值、将其返回出去
}
}
return null; // 没有就返回null
}
复制代码
HashTable的核心内容扩容机制
扩容是在元素添加时、判断数组的大小是否能够存入下一个值、而做的操作扩容
----------------- 添加方法 ------------------
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) { // value 不能为null 否者抛出异常
throw new NullPointerException();
}
// 将构造中已经初始化的赋值给tab
Entry<?,?> tab[] = table;
// 计算hash值
int hash = key.hashCode();
// 计算下标
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings(“unchecked”)
// 找到该下标中的节点链表
Entry<K,V> entry = (Entry<K,V>)tab[index];
// 遍历该链表下的节点
for(; entry != null ; entry = entry.next) {
// 判断hash值是否相同等、内容是否相等
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value; // 将旧的value值赋值给old
entry.value = value; // 将新的value值赋值给旧的value值
return old; // 将旧的value值返回
}
}
// 如果链表没有重复的则进行添加在其他位置上
addEntry(hash, key, value, index); // 后面来说这个方法
return null;
}
---------------addEntry()-----------------
private void addEntry(int hash, K key, V value, int index) {
modCount++; // 修改次数++
Entry<?,?> tab[] = table;
// 元素数量大于等于阈值进行扩容操作threshold 默认为8
if (count >= threshold) {
// Rehash the table if the threshold is exceeded
rehash(); // 扩容主要方法
tab = table;
hash = key.hashCode();
index = (hash & 0x7FFFFFFF) % tab.length; // 扩容后重新计算索引下标
}
// Creates the new entry.
@SuppressWarnings(“unchecked”)
// 第一次这个节点为null
Entry<K,V> e = (Entry<K,V>) tab[index];
// 创建一个新的节点、赋值给tab[求出下标索引的位置上]
tab[index] = new Entry<>(hash, key, value, e);
count++; // 长度++
}
---------------rehash()-----------------
protected void rehash() {
int oldCapacity = table.length; // 先获取数组的长度
Entry<?,?>[] oldMap = table; // 获取数据
// overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1; // 扩容成2倍+1
// 判断新扩容的容量大小是否超过默认的最大值
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
// 如果超过将最大值赋值给新容量
newCapacity = MAX_ARRAY_SIZE;
}
// newCapacity 获取到新容量的大小后创建一个最新容量大小的数组
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];
modCount++; // 修改次数++
// 计算新的threshold(阈值) 、 超过就进行扩容操作
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap; // 重新给数组赋值
// 数据迁移遍历数据、将原来数组中的数据放到新数组中
for (int i = oldCapacity ; i-- > 0 😉 {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)
Kafka实战笔记
关于这份笔记,为了不影响大家的阅读体验,我只能在文章中展示部分的章节内容和核心截图
- Kafka入门
- 为什么选择Kafka
- Karka的安装、管理和配置
- Kafka的集群
- 第一个Kafka程序
afka的生产者
- Kafka的消费者
- 深入理解Kafka
- 可靠的数据传递
- Spring和Kalka的整合
- Sprinboot和Kafka的整合
- Kafka实战之削峰填谷
- 数据管道和流式处理(了解即可)
- Kafka实战之削峰填谷
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
(img-dhiCo17n-1713631369832)]
- Kafka的消费者
- 深入理解Kafka
- 可靠的数据传递
[外链图片转存中…(img-9fp60VMa-1713631369832)]
[外链图片转存中…(img-RTKVsuMa-1713631369832)]
- Spring和Kalka的整合
- Sprinboot和Kafka的整合
- Kafka实战之削峰填谷
- 数据管道和流式处理(了解即可)
[外链图片转存中…(img-HJoNTsxp-1713631369833)]
- Kafka实战之削峰填谷
[外链图片转存中…(img-0slkTPs6-1713631369833)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!