Java中对HashMap的深度分析_MySQL
在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键。由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题。找遍了大大小小的论坛,也把《Java 虚拟机规范》,《apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector》,和《Thinking in Java》翻了也找不到很好的答案,于是一气之下把JDK的 src 解压出来研究,扩然开朗,遂写此文,跟大家分享感受和顺便验证我理解还有没有漏洞。 这里就拿HashMap来研究吧。
HashMap可谓JDK的一大实用工具,把各个Object映射起来,实现了“键--值”对应的快速存取。但实际里面做了些什么呢?
在这之前,先介绍一下负载因子和容量的属性。大家都知道其实一个 HashMap 的实际容量就 因子*容量,其默认值是 16×0.75=12; 这个很重要,对效率很一定影响!当存入HashMap的对象超过这个容量时,HashMap 就会重新构造存取表。这就是一个大问题,我后面慢慢介绍,反正,如果你已经知道你大概要存放多少个对象,最好设为该实际容量的能接受的数字。
两个关键的方法,put和get:
先有这样一个概念,HashMap是声明了 Map,Cloneable, Serializable 接口,和继承了 AbstractMap 类,里面的 Iterator 其实主要都是其内部类HashIterator 和其他几个 iterator 类实现,当然还有一个很重要的继承了Map.Entry 的 Entry 内部类,由于大家都有源代码,大家有兴趣可以看看这部分,我主要想说明的是 Entry 内部类。它包含了hash,value,key 和next 这四个属性,很重要。put的源码如下
public Object put(Object key, Object value) {
Object k = maskNull(key);
这个就是判断键值是否为空,并不很深奥,其实如果为空,它会返回一个static Object 作为键值,这就是为什么HashMap允许空键值的原因。
int hash = hash(k);
int i = indexFor(hash, table.length);
这连续的两步就是 HashMap 最牛的地方!研究完我都汗颜了,其中 hash 就是通过 key 这个Object的 hashcode 进行 hash,然后通过 indexFor 获得在Object table的索引值。
table???不要惊讶,其实HashMap也神不到哪里去,它就是用 table 来放的。最牛的就是用 hash 能正确的返回索引。其中的hash算法,我跟JDK的作者 Doug 联系过,他建议我看看《The art of programing vol3》可恨的是,我之前就一直在找,我都找不到,他这样一提,我就更加急了,可惜口袋空空啊!!!
不知道大家有没有留意 put 其实是一个有返回的方法,它会把相同键值的 put 覆盖掉并返回旧的值!如下方法彻底说明了 HashMap 的结构,其实就是一个表加上在相应位置的Entry的链表:
for (Entry e = table[i]; e != null; e = e.next) {
if (e.hash == hash && eq(k, e.key)) {
Object oldvalue = e.value;
e.value = value; //把新的值赋予给对应键值。
e.recordAccess(this); //空方法,留待实现
return oldvalue; //返回相同键值的对应的旧的值。
}
}
modCount++; //结构性更改的次数
addEntry(hash, k, value, i); //添加新元素,关键所在!
return null; //没有相同的键值返回
}
我们把关键的方法拿出来分析:
void addEntry(int hash, Object key, Object value, int bucketIndex) {
table[bucketIndex] = new Entry(hash, key, value, table[bucketIndex]);
因为 hash 的算法有可能令不同的键值有相同的hash码并有相同的table索引,如:key=“33”和key=Object g的hash都是-8901334,那它经过indexfor之后的索引一定都为i,这样在new的时候这个Entry的next就会指向这个原本的table[i],再有下一个也如此,形成一个链表,和put的循环对定e.next获得旧的值。到这里,HashMap的结构,大家也十分明白了吧?
if (size++ >= threshold) //这个threshold就是能实际容纳的量
resize(2 * table.length); //超出这个容量就会将Object table重构
所谓的重构也不神,就是建一个两倍大的table(我在别的论坛上看到有人说是两倍加1,把我骗了),然后再一个个indexfor进去!注意!!这就是效率!!如果你能让你的HashMap不需要重构那么多次,效率会大大提高!
说到这里也差不多了,get比put简单得多,大家,了解put,get也差不了多少了。对于collections我是认为,它是适合广泛的,当不完全适合特有的,如果大家的程序需要特殊的用途,自己写吧,其实很简单。(作者是这样跟我说的,他还建议我用LinkedHashMap,我看了源码以后发现,LinkHashMap其实就是继承HashMap的,然后override相应的方法,有兴趣的同人,自己looklook)建个 Object table,写相应的算法,就ok啦。
举个例子吧,像 Vector,list 啊什么的其实都很简单,最多就多了的同步的声明,其实如果要实现像Vector那种,插入,删除不多的,可以用一个Object table来实现,按索引存取,添加等。
如果插入,删除比较多的,可以建两个Object table,然后每个元素用含有next结构的,一个table存,如果要插入到i,但是i已经有元素,用next连起来,然后size++,并在另一个table记录其位置。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











해시맵의 확장 메커니즘은 용량을 다시 계산하고 원래 배열을 새 배열로 교체하는 것입니다. 원본 배열의 모든 데이터를 다시 계산하여 새 배열을 삽입한 후 새 배열을 가리키며, 용량 확장 전 배열이 최대값에 도달한 경우 직접 임계값을 최대 정수로 설정하고 반환합니다.

HashMap 클래스의 put() 메소드를 사용하여 HashMap에 키-값 쌍을 삽입하는 방법 HashMap은 Java 컬렉션 프레임워크에서 매우 중요한 클래스입니다. 실제 개발에서는 HashMap 클래스의 put() 메서드를 사용하여 쉽게 구현할 수 있는 키-값 쌍을 HashMap에 삽입해야 하는 경우가 많습니다. HashMap의 put() 메소드의 서명은 다음과 같습니다: Vput(Kkey,Vvalue)

해시 연산 //해시 테이블의 필드에 값을 할당합니다. 성공하면 1을, 실패하면 0을 반환합니다. 해시 테이블이 없으면 테이블이 먼저 생성된 후 값이 할당됩니다. 필드가 이미 있으면 이전 값을 덮어씁니다. $ret=$redis->hSet('user','realname','jetwu');//해시 테이블에서 지정된 필드의 값을 가져옵니다. 해시 테이블이 없으면 false를 반환합니다. $ret=$redis->hGet('사용자','지역

1. Map은 기본적으로 HashMap을 사용할 수 있는데, HashMap에 문제가 있다고 설명합니다. 즉, HashMap을 반복하는 순서가 HashMap이 배치된 순서와 다르거나 순서가 맞지 않는다는 것입니다. HashMap의 이러한 단점은 종종 문제를 야기합니다. 일부 시나리오에서는 LinkedHashMap인 정렬된 맵을 기대하기 때문입니다. 2. 차이점 인스턴스 publicstaticvoidmain(String[]args){Mapmap=newLinkedHashMap();map.put("apple","Apple");map.put("

Java 문서 해석: HashMap 클래스의 containKey() 메소드 사용법에 대한 자세한 설명이 필요합니다. 소개: HashMap은 Java에서 일반적으로 사용되는 데이터 구조입니다. ContainsKey() 메서드는 HashMap에 지정된 키가 포함되어 있는지 확인하는 데 사용됩니다. 이 문서에서는 HashMap 클래스의 containKey() 메서드를 사용하는 방법을 자세히 설명하고 구체적인 코드 예제를 제공합니다. 1. 계속

1. 싱글턴 패턴이란 무엇인가요? 싱글톤 패턴은 객체의 특정 인스턴스를 생성하는 데 사용되는 객체 생성 패턴으로, 시스템에서 클래스의 인스턴스가 하나만 생성되도록 할 수 있습니다. Java로 구현된 싱글톤은 가상 머신의 범위 내에 있으므로 클래스를 로드하는 기능은 가상 머신에 속하므로 가상 머신은 자체 ClassLoad를 통해 싱글톤 클래스를 로드할 때 클래스의 인스턴스를 생성합니다. Java 언어에서 이러한 동작은 두 가지 주요 이점을 가져올 수 있습니다. 1. 자주 사용되는 객체의 경우 객체 생성에 소요되는 시간을 생략할 수 있습니다. 이는 중량 객체에 대한 시스템 오버헤드가 매우 큽니다. 2. 새로운 작업 수가 많기 때문입니다. 감소하면 시스템 메모리 사용 빈도도 줄어들어 GC 압력이 감소합니다.

Laravel은 현재 가장 인기 있는 PHP 웹 프레임워크 중 하나이며 개발자에게 많은 강력한 기능과 구성 요소를 제공하며 LaravelHash도 그 중 하나입니다. LaravelHash는 비밀번호를 안전하게 유지하고 애플리케이션의 사용자 데이터를 더욱 안전하게 만드는 데 사용할 수 있는 비밀번호 해싱용 PHP 라이브러리입니다. 이 글에서는 LaravelHash의 작동 방식과 이를 사용하여 비밀번호를 해시하고 확인하는 방법을 알아봅니다. 라라 학습을 위한 필수 지식

JavaMap은 Java 표준 라이브러리에서 일반적으로 사용되는 데이터 구조로, 키-값 쌍의 형태로 데이터를 저장합니다. Map의 성능은 애플리케이션의 실행 효율성에 매우 중요합니다. Map의 성능이 좋지 않으면 애플리케이션이 느리게 실행되거나 충돌할 수도 있습니다. 1. 적절한 맵 구현 선택 Java는 HashMap, TreeMap 및 LinkedHashMap을 포함한 다양한 맵 구현을 제공합니다. 각 맵 구현에는 고유한 장점과 단점이 있습니다. 맵 구현을 선택할 때는 애플리케이션의 특정 요구 사항에 따라 적절한 구현을 선택해야 합니다. HashMap: HashMap은 가장 일반적으로 사용되는 맵 구현입니다. 해시 테이블을 사용하여 데이터를 저장하고 삽입, 삭제 및 검색 속도가 더 빠릅니다.
