解析JAVA 常用集合内部机制原理
对于常用的集合大家都不陌生,但是深入到内部原理可能都是一知半解,通过阅读源码理解如下。
ArrayList
ArrayList内部就是一个默认大小为10的动态对象数组容器,每当add一个新数据的时候,如果大于原来的容器大小,则会通过Arrays.copyOf把容器大小增加到原来的1.5倍,以此类推。当可以预知数据大小,可以通过initialCapacity来默认设置动态数据的大小,减少扩容带来的资源消耗。
时间复杂度:
get() - 直接读取下标 - O(1)
add(E) - 直接在后面添加 - O(1)
add(idnex, E) - 插入数据后需要移动后面的数据 - O(n)
remove(index) - 删除后需要移动 - O(n)
LinkedList
LinkedList内部是一个双向链表,add新数据的时候,其实就是调用linklast在链表尾部插入数据。删除的时候直接找到对应数据,替换掉链表的前后节点即可。
时间复杂度:
get() - 需要遍历 - O(n)
add(E) - 调用linklast直接添加在最后 - O(1)
add(index, E) - 需要先查找到原来index位置的数据,再重新指定链表前后的数据 - O(n)
remove() - 直接调用removeLast删除最后数据 - O(1)
remove(index) - 需要先查找到原来index位置的数据 - O(n)
HashMap
HashMap内部其实是一个数组,每个数组下是一个单向链表。HashMap中的数组是一个取名为Entry的类,类包含(key, value, next)这几个属性。存放规则为,数组下标按hash(key)%len获得,取得数组后则查找对应数组的值。HashMap还有个负载因子(默认0.75),当里面数组填满了75%的时候,会进行扩展到原来大小的2倍。
那么问题来了,如果在put的时候,取到hash(key)%len的值相等时不就冲突了?HashMap的处理方法是:原来有一个Entry[0] = A,此时来一个index也是0的B,则会把Entry[0] = B,B.next = A,又来一个C的时候,则会把Entry[0] = C,C.next = B,以此类推。这样Entry就会形成一个链表,取的时候则是遍历链表取值。
这里需要提到的是,使用hashMap的时候,引入的key对象必须重写hashCode()和equal()两个函数,原因可以参考源码判断条件(if (e.hash == hash && ((k = e.key) == key || key.equals(k)))),如果hashCode()没重写,则压根找不到对应数组,如果equal()没重写,则无法判断key值的内容是否相等。
public V put(K key, V value) { if (key == null) return putForNullKey(value); //null总是放在数组的第一个链表中 int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); //遍历链表 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; //如果key在链表中已存在,则替换为新value if (e.hash == hash && ((k = e.key) == key || key.equals(k))){ V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
补充:
在java8之后hashmap进行了优化:由于单向链表的查询时间复杂度为O(n),在极端情况下可能存在性能问题,于是java8针对链表长度大于8的情况会使用时间复杂度为O(log n)的红黑树进行存储来提升存储查询的效率。
LinkedHashMap
LinkedHashMap内部双向链表和HashMap的结合,支持多种迭代顺序,默认按插入顺序,也可以按访问顺序。
访问顺序(accessOrder=true):调用过get访问的元素会放到链尾,迭代会从链首开始
插入顺序(accessOrder=false):按插入顺序迭代出来
TreeMap
TreeMap内部是基于红黑树实现的,并且默认会通过compareTo按照key类型进行自然排序。TreeSet的低层是TreeMap。
Atas ialah kandungan terperinci 解析JAVA 常用集合内部机制原理. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

Video Face Swap
Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

Java ialah bahasa pengaturcaraan popular yang boleh dipelajari oleh pembangun pemula dan berpengalaman. Tutorial ini bermula dengan konsep asas dan diteruskan melalui topik lanjutan. Selepas memasang Kit Pembangunan Java, anda boleh berlatih pengaturcaraan dengan mencipta program "Hello, World!" Selepas anda memahami kod, gunakan gesaan arahan untuk menyusun dan menjalankan program, dan "Hello, World!" Pembelajaran Java memulakan perjalanan pengaturcaraan anda, dan apabila penguasaan anda semakin mendalam, anda boleh mencipta aplikasi yang lebih kompleks.
