Java集合总结(架构师之路 )
JAVA架构师之路
本系列文章均是博主原创,意在记录学习上的知识,同时一起分享学习心得。
第一章
第一节 Java集合总结(架构师之路 )
第二节 Java多线程(架构师之路 )
前言
本章内容是博主学习路程的一些重点笔记,主要是为了方便自己以后的回看,同时也跟大家一起分享心得。
若您有发现不对的地方,请私信博主进行更正,谢谢。目录
- JAVA架构师之路
- 1. Java集合概述
- 2、Collection
- 2.1 Set
- 2.1.1 HashSet
- 2.1.2 LinkedHashSet
- 2.1.3 TreeSet
- 2.2 List
- 2.2.1 ArrayList
- 2.2.2 LinkedList
- 2.2.1 Vector
- 2.3 Queue
- 2.2.1 BlokingQueue
- 2.2.1.1 ArrayBlockingQueue
- 2.2.1.2 LinkedBlockingQueue
- 2.2.2 Deque
- 2.2.2.1 LinkedBlockingDeque
- 3、Map
- 3.1 Hashtable
- 3.2 HashMap
- 3.2.1 LinkedHashMap
- 3.3 TreeMap
- 3.4 拓展知识
1. Java集合概述
集合框架:用于存储数据的容器。
1)集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
2)任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
集合的顶级父类为Collection、Map,下图为各自的实现类:
2、Collection
Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements)。一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。
所有实现Collection接口的类都必须提供两个标准的构造函数:无参数的构造函数用于创建一个空的Collection,有一个Collection参数的构造函数用于创建一个新的Collection,这个新的Collection与传入的Collection有相同的元素。后一个构造函数允许用户复制一个Collection。
2.1 Set
Set继承了Collection接口,它本身也是一个接口,留给子类实现。
2.1.1 HashSet
- HashSet实现了Set接口,其特点是元素无序、不可重复。
- 其内部是使用一个HashMap作为实际存储容器,所以其特性也跟HashMap相似。
其add()方法的执行过程如下:
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();public boolean add(E e) {return map.put(e, PRESENT)==null;
}
可以看出HashSet的add方法其实是使用了HashMap,将其存储的元素值,作为HashMap的key,用一个空的Object作为值。从而达到其元素无序、不可重复的特性。
使用实例代码:
public static void main(String[] args) {Set s = new HashSet();s.add("1");s.add("1");s.add("2");System.out.println(s.size());
}
2.1.2 LinkedHashSet
- LinkedHashSet继承了HashSet,其特点是元素有序、不可重复。
- 以哈希表和链表实现的set集合接口,迭代方式和我们预想的一致(因为查询速度的原因底层使用了散列,但是看起来它使用了链表来维护元素的插入顺序),这和hashset实现方式是不同的,因为在它所有的插入过程中都保持了一个双向链表的属性。
- 链表定义了迭代顺序,即为我们向集合set中插入元素的顺序。注意如果一个元素被重复插入到集合中并不会改变集合的插入顺序。(如果元素e被添加到集合s中,会调用s.add(e)方法,但是s.contains(e)会在s.add(e)方法之前调用并返回true)。
示例代码:
public static void main(String[] args) {LinkedHashSet<String> set = new LinkedHashSet();set.add("1");set.add("2");set.add("3");set.add("1");for (String s:set) {System.out.println(s);}
}
2.1.3 TreeSet
- TreeSet 类继承了 AbstractSet抽象类和实现了NavigableSet接口,间接也实现 SortedSet 接口,元素不能重复;
- 由于 SortedSet 接口能对元素升序排序(也叫自然排序),TreeSet 类也会对实现了 Comparable 接口
的类的对象自动排序,或者根据创建 TreeSet 时提供的 Comparator 进行排序; - 底层依赖于 NavigableMap,元素没有索引;
- 通过红黑树实现,不允许放入null值;
- 存储大量的需要进行快速检索的排序信息时,TreeSet 是一个很好的选择;
public static void treeSet(){TreeSet<Integer> treeSet = new TreeSet<Integer>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {// 返回值大于0,倒序return o1 - o2;}});treeSet.add(1);treeSet.add(2);treeSet.add(3);Iterator<Integer> in = treeSet.iterator();while (in.hasNext()) {System.out.println(in.next());}
}
2.2 List
List继承了Collection接口,其本身也是一个接口,主要特点是定义一个有序、元素可重复的容器。
2.2.1 ArrayList
ArrayList实现了List接口,其主要特点是有序、元素可重复。
- 底层为一个Object数组
- 数组初始化容量为10
- 扩容方式,先根据目前的容量*1.5倍计算出新容量;然后将新容量跟目前要装载的数据长度再做比较,取较大值;最后判断新容量是否大于int类型的最大值-8,若为大于,再将int最大值跟目前要装载的数据长度比较,若为大于,取int类型的最大值-8,否则取int类型的最大值;
// 扩容方式
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}
代码实例:
public static void arrayList(){List<Integer> list = new ArrayList();list.add(1);list.add(1);list.add(2);list.add(3);for (Integer i : list) {System.out.println(i);}
}
2.2.2 LinkedList
- LinkedList也实现了List接口,相对于ArrayList来说,它们的最大区别在于底层数据结构不同,LinkedList的底层是一个双向链表,这也决定了它的最大优点,那就是对于数据的修改比ArrayList更加方便快捷。
- 相对于ArrayList,LinkedList插入是更快的。因为LinkedList不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,类似于插入数据,删除数据时,LinkedList也优于ArrayList,其时间复杂度仅为O(1),而ArrayList删除数据是开销很大的,因为这需要重排数组中的所有数据(除了最后一个元素)。
- 底层维护了两个Node节点,分别为first和last。node节点数据结构包含前后node,以及自身的值。
private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}
实例代码:
public static void linkedList(){LinkedList<Integer> linkedList = new LinkedList();linkedList.add(1);linkedList.add(2);linkedList.add(3);System.out.println(linkedList.get(2));
}
2.2.1 Vector
- Vector和ArrayList的实现方式是一样的,区别在于Vector在某些方法上加了synchronized同步关键字。
public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;
}
实例代码:
public static void vector(){Vector<Integer> vector = new Vector();vector.add(1);vector.add(2);vector.add(3);Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {vector.add(13);}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {try {Thread.sleep(1000L);} catch (InterruptedException e) {e.printStackTrace();}vector.add(15);}});t2.run();t1.run();for (Integer i : vector) {System.out.println(i);}
}
2.3 Queue
Queue是java中实现队列的接口,他继承Collection接口,总共只有6个方法。
Queue的6个方法分类:
压入元素(添加):add()、offer()
相同:未超出容量,从队尾压入元素,返回压入的那个元素。
区别:在超出容量时,add()方法会对抛出异常,offer()返回false
弹出元素(删除):remove()、poll()
相同:容量大于0的时候,删除并返回队头被删除的那个元素。
区别:在容量为0的时候,remove()会抛出异常,poll()返回false
获取队头元素(不删除):element()、peek()
相同:容量大于0的时候,都返回队头元素。但是不删除。
区别:容量为0的时候,element()会抛出异常,peek()返回null。
2.2.1 BlokingQueue
BlokingQueue是继承了Queue接口,本身也是一个接口。
特点:
- 阻塞队列
- 向队列中添加元素时,队列的长度已满阻塞当前添加线程,直到队列未满或者等待超时;
- 从队列中获取元素时,队列中元素为空 ,会将获取元素的线程阻塞,直到队列中存在元素 或者等待超时。
方法简解
- puts操作
add(E e) : 添加成功返回true,失败抛IllegalStateException异常
offer(E e) : 成功返回 true,如果此队列已满,则返回 false(如果添加了时间参数,且队列已满也会阻塞)
put(E e) :将元素插入此队列的尾部,如果该队列已满,则一直阻塞 - takes操作
remove(Object o) :移除指定元素,成功返回true,失败返回false
poll() : 获取并移除此队列的头元素,若队列为空,则返回 null(如果添加了时间参数,且队列中没有数据也会阻塞)
take():获取并移除此队列头元素,若没有元素则一直阻塞。
peek() :获取但不移除此队列的头;若队列为空,则返回 null。 - other操作
contains(Object o):队列中是否包含指定元素
drainTo(Collection<? super E> c):队列转化为集合
2.2.1.1 ArrayBlockingQueue
ArrayBlockingQueue是一个由数组支持的有界阻塞队列。
- 底层是基于数组的BlockingQueue的实现。
- 容纳大小是固定的,不可扩展。
- 线程安全的。
- 不接受 null 元素。
- 公平性 (fairness)可以在构造函数中指定,如果为true,则按照 FIFO 顺序访问插入或移除时受阻塞线程的队列;如果为 false,则访问顺序是不确定的。
实例代码:
public static void arrayBlockingQueue() throws InterruptedException {BlockingQueue<String> blockingQueue = new ArrayBlockingQueue(10);blockingQueue.add("2");blockingQueue.offer("3");blockingQueue.put("1");blockingQueue.remove("1");blockingQueue.poll();blockingQueue.take();blockingQueue.peek();blockingQueue.contains("2");blockingQueue.drainTo(new LinkedList<>());
}
2.2.1.2 LinkedBlockingQueue
LinkedBlockingQueue是一个单向链表实现的阻塞队列,可以定义为无界队列也可以是有界队列。这里用了两个锁,读写可以同时进行,条件满足时,往队尾加入,对头出列。
代码示例
// 单向链表
static class Node<E> {E item;/*** One of:* - the real successor Node* - this Node, meaning the successor is head.next* - null, meaning there is no successor (this is the last node)*/Node<E> next;Node(E x) { item = x; }
}
public static void linkedBlockingQueue() throws InterruptedException {BlockingQueue<String> blockingQueue = new LinkedBlockingQueue();blockingQueue.put("1");blockingQueue.poll();blockingQueue.offer("e");blockingQueue.remove();
}
2.2.2 Deque
Deque接口是“double ended queue”的缩写(通常读作“deck”),即双端队列,支持在队列的两端插入和删除元素,继承Queue接口。大多数的实现对元素的数量没有限制,但这个接口既支持有容量限制的deque,也支持没有固定大小限制的。
Deque接口定义了在两端访问元素的方法,主要包括insert、remove和examine。和Queue定义一样,所有这些方法存在两种形式:一种如果操作失败则抛出异常,另一种则返回一个特殊值(null或false)。后者主要是为有容量限制的队列实现的。
Deque的12种方法总结如下:
. | First Element (Head) | ← | Last Element (Tail) | ← |
---|---|---|---|---|
. | Throws exception | Special value | Throws exception | Special value |
Insert | addFirst(e) | offerFirst(e) | addLast(e) | offerLast(e) |
Remove | removeFirst() | pollFirst() | removeLast() | pollLast() |
Examine | getFirst() | peekFirst() | getLast() | peekLast() |
当deque用作queue时,则表现出FIFO的行为,元素从队尾加入,在队首移除,从Queue接口继承来的方法和Deque中的一些方法等
2.2.2.1 LinkedBlockingDeque
LinkedBlockingDeque是双向链表实现的阻塞队列,可以被当作堆栈、双端队列进行操作。
代码示例
// 双向链表结构
/** Doubly-linked list node class */
static final class Node<E> {/*** The item, or null if this node has been removed.*/E item;/*** One of:* - the real predecessor Node* - this Node, meaning the predecessor is tail* - null, meaning there is no predecessor*/Node<E> prev;/*** One of:* - the real successor Node* - this Node, meaning the successor is head* - null, meaning there is no successor*/Node<E> next;Node(E x) {item = x;}
}
public static void linkedBlockingDeque() throws InterruptedException {BlockingQueue<String> blockingQueue = new LinkedBlockingDeque<>();blockingQueue.put("1");blockingQueue.poll();blockingQueue.offer("e");blockingQueue.remove();
}
3、Map
Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。
3.1 Hashtable
Hashtable简介:key和value的值均不允许为null;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢,只有hashtable是继承自Dictionary抽象类的,hashMap和treeMap都继承自AbstractMap抽象类,LinkedHashMap继承自hashMap。
- 底层为一个Entry数组。
- 传入的值不能为null。
- 它是线程安全的。
// 源码add()
public synchronized V put(K key, V value) {// Make sure the value is not nullif (value == null) {throw new NullPointerException();}// Makes sure the key is not already in the hashtable.Entry<?,?> tab[] = table;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) {if ((entry.hash == hash) && entry.key.equals(key)) {V old = entry.value;entry.value = value;return old;}}addEntry(hash, key, value, index);return null;
}
实例代码
public static void hashTable() {Hashtable map = new Hashtable();map.put("1", "2");map.get("1");map.remove("1");
}
3.2 HashMap
HashMap的实现了Map接口。
- 它是无序的,非同步的。
- key值唯一,最多只允许一条记录的key值为Null(多条会覆盖);允许多条记录的Value为 Null。
- 底层是一个Node数组,数组默认初始大小是16。
- Node数组的元素默认是一个链表,当链表长度>=8时,会转换成一颗红黑树。
- 最大容积是2^30, 有阈值、负载系数等。。
- 添加元素时,先根据key值计算得出hash值,根据hash值进行运算得出数组的下标,最后将元素插入该数组下标对应的node链表末尾。
名词解析
红黑树。一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。
通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路径会比其他路径长出俩倍,因而是接近平衡的。
阈值。当元素长度超过阈值时,会自动扩张数组大小。阈值初始值为:160.75=12,16为数组默认长度,0.75为默认负载系数;阈值后面扩充公式:当前阈值2=新阈值。
node数组扩充公式。当前数组大小 * 2=新数组大小。
// 扩充代码
final Node<K,V>[] resize() {Node<K,V>[] oldTab = table;int oldCap = (oldTab == null) ? 0 : oldTab.length;int oldThr = threshold;int newCap, newThr = 0;if (oldCap > 0) {if (oldCap >= MAXIMUM_CAPACITY) {threshold = Integer.MAX_VALUE;return oldTab;}else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&oldCap >= DEFAULT_INITIAL_CAPACITY)newThr = oldThr << 1; // double threshold}else if (oldThr > 0) // initial capacity was placed in thresholdnewCap = oldThr;else { // zero initial threshold signifies using defaultsnewCap = DEFAULT_INITIAL_CAPACITY;newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);}if (newThr == 0) {float ft = (float)newCap * loadFactor;newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?(int)ft : Integer.MAX_VALUE);}threshold = newThr;@SuppressWarnings({"rawtypes","unchecked"})Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];table = newTab;...}
示例代码
public static void hashMap() {HashMap<String, String> hashMap = new HashMap<>();for (int i = 0; i < 14; i++) {if (i == 12) {int a = 1;System.out.println(a+"");}hashMap.put("" + i, "2");}
}
3.2.1 LinkedHashMap
LinkedHashMap继承了HashMap。
- 它是有序的。
- key和value均允许为空,非同步的。
- 底层维护了首尾两个Entry双向链表,且Entry继承了HashMap的Node类。
- 除了底层数据结构与HashMap不同之外,其他大致相同。
// LinkedHashMap底层数据结构
transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;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);}
}
实例代码
public static void linkedHashMap() {LinkedHashMap<Integer, String> l = new LinkedHashMap<>();l.put(1, "a");l.put(2, "b");System.out.println(l);
}
3.3 TreeMap
TreeMap实现了NavigableMap,间接实现了SortedMap接口。
- 它是有序的,默认根据key按升序排序,可以自定义比较器。
- TreeMap不允许key的值为null,非同步的。
- 底层是一颗红黑树。
private final Comparator<? super K> comparator;
private transient Entry<K,V> root;// 根节点static final class Entry<K,V> implements Map.Entry<K,V> {K key;V value;Entry<K,V> left;Entry<K,V> right;Entry<K,V> parent;boolean color = BLACK;...
}
示例代码
public static void treeMap() {TreeMap<Integer, String> treeMap = new TreeMap<>();treeMap.put(2, "b");treeMap.put(1, "a");treeMap.put(4, "d");treeMap.put(3, "c");System.out.println(treeMap);}
3.4 拓展知识
- IdentityHashMap
IdentityHashMap 是一个实现了 Map 接口的哈希表,它使用了引用相等来替代对象相等,即只有 k1 == k2 的情况下,才认为这两个对象相等。参考链接 Java8 - IdentityHashMap源码 - SortedMap
SortedMap 接口继承自 Map 接口,提供了按照 Key 排序的功能,即 keySet、values、entrySet 结果集有序。参考链接 Java集合学习十三 SortedMap - NavigableMap
NavigableMap扩展了 SortedMap,具有了针对给定搜索目标返回最接近匹配项的导航方法。参考链接 Java集合之NavigableMap与NavigableSet接口 - WeakHashMap
WeakHashMap,此种Map的特点是,当除了自身有对key的引用外,此key没有其他引用那么此map会自动丢弃此值。参考链接 解析WeakHashMap与HashMap的区别详解
Java集合总结(架构师之路 )相关推荐
- java 资深_Java架构师之路:从Java码农到资深架构师
写在开篇 不管是开发.测试.运维,每个技术人员心里都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使我们不断地努力和提升自己. 然而" ...
- 从0到1—JAVA大数据架构师之路
第一阶段:java基础及进阶 第二阶段:数据库VUE&SSM 第三阶段:SSM架构及后端开发项目 第四阶段:微服务之SpingCloudAlibaba 第五阶段:微服务之Spingcloud ...
- python爬虫架构师之路_一位资深 架构师大牛给予Java技术提升的学习路线建议
一位资深 架构师大牛给予Java技术提升的学习路线建议 对于工作多年的程序员而言,日后的职业发展无非是继续专精技术.转型管理和晋升架构师三种选择. 架构师在一家公司有多重要.优秀架构师需要具备怎样的素 ...
- Java高级架构师之路核心知识整理
小编整理出一篇Java高级架构师之路的核心知识,同时也是面试时面试官必问的知识点,篇章也是包括了很多知识点,其中包括了有基础知识.Java集合.JVM.多线程并发.spring原理.微服务.Netty ...
- java架构师之路:JAVA程序员必看的15本书的电子版下载地址
java架构师之路:JAVA程序员必看的15本书的电子版下载地址 作为Java程序员来说,最痛苦的事情莫过于可以选择的范围太广,可以读的书太多,往往容易无所适从.我想就我自己读过的技术书籍中挑选出来一 ...
- 架构师变形记:讲述Java码农到年薪100万架构师之路
最近有不少朋友问我怎样才能成为年薪百万的架构师,我听到他这样问,首先想到的是什么样的人才可以称之为架构师,然后我给他总结了他需要攻克的3个难点: 1.接触不到一线实战架构设计,尤其是有一定的技术深度和 ...
- java架构师什么学校好_Java架构师之路:年薪八十万的架构师课程
原标题:Java架构师之路:年薪八十万的架构师课程 不管是开发.测试.运维,每个技术人员心里都有一个成为技术大牛的梦,毕竟"梦想总是要有的,万一实现了呢"!正是对技术梦的追求,促使 ...
- JAVA架构师之路十五:设计模式之策略模式
JAVA架构师之路十四:设计模式之模板模式 策略模式 1. 策略模式 2. 优惠券案例 3. 支付案例 人生的游戏不在于拿了一副好牌,而在于怎样去打好坏牌,世上没有常胜将军,勇于超越自我者才能得到最后 ...
- JAVA架构师之路十六:设计模式之责任链模式
JAVA架构师之路十五:设计模式之策略模式 责任链模式 1. 责任链模式 2. 登陆案例 3. 登陆案例优化 人生的游戏不在于拿了一副好牌,而在于怎样去打好坏牌,世上没有常胜将军,勇于超越自我者才能得 ...
最新文章
- html 表格自动计算,HTML表格中的JavaScript计算
- 石头扫地机器人加速异响_米家扫地机器人有异响怎么办
- Kali Linux渗透测试实战 2.2 操作系统指纹识别
- MyBatis-学习笔记10【10.JNDI扩展知识】
- 计算机基础知识教程职称怎么计算,2017年职称计算机考试基础知识教程详解(二十)...
- Jackson快速入门
- 高考python必考题目_假如高考考python编程,这些题目你会几个呢?
- sql datetime字段 取年月日_写一手好SQL,你该从哪里入手?
- php web长时间不操作退出,Ecshop管理员登陆后台后短时间不操作自动退出的解决方法...
- Linux的Cache Memory(缓存内存)机制
- 472. 连接词(每日一难phase2--day24)
- 带通 带阻滤波器 幅频响应_方程推导:二阶有源带通滤波器设计!(内附教程+原理图+视频+代码下载)...
- 1、AD创建模板和导入
- 免费网站流量统计服务汇总
- 程序猿头头(js数组reverse,sort,concat,slice, splice)
- 自学简单编程可行吗?
- java编译器eclipse_Java 调用 Eclipse的编译器 JDT
- 【Python】原来处理大文件也可以这么简单?
- poiExcel格式设置,很好用,感谢大佬
- 【分库分表】企业级分库分表实战方案与详解(MySQL专栏启动)