在处理数据的过程中经常会需要一个容器来存储某一类型的数据,Java 中的数组就是这样一种容器。但 Java 中的数组有其局限性,定义后的数组长度不可变,超出数组长度后就不能再存放数据了。而很多时候我们并不知道数据到底有多少,所以就需要有不定长的容器来存放数据,这就是集合,Java 中的集合都采用了泛型实现,可以存入任何类型的对象数据。

Java 中的数组:

package test;import java.util.Arrays;public class Arr{ public static void main(String[] args) { int[] arr = new int[2]; arr[0] = 1; arr[1] = 2; // arr[2] = 3; // 编译出错 System.out.println(Arrays.toString(arr)); // 输出:[1, 2] }}

Java 中的集合主要分为四类:

  1. List 列表,有序,可重复
  2. Queue 队列,有序,可重复
  3. Set 集合,不可重复
  4. Map 映射,无序,键唯一,值不唯一

每种集合类型下都包含多个具体的实现类,如:

1. List 列表,有序、可重复

常用的 List 实现类有:ArrayList、LinkedList、Vector、Stack。

1.1 ArrayList 列表

ArrayList 数组列表,有序,可重复,内部是通过 Array 实现。

初始化对象时,如果没有传大小,则列表的大小为 DEFAULT_CAPACITY 的默认值 10。当列表容量不够时,继续往列表中追加元素,则通过数组拷贝,对原数组进行扩容,扩容的方式为 int newCapacity = oldCapacity + (oldCapacity >> 1),即新数组容量 newCapacity 为 10 + 10/2 = 15。如果一次性追加多个元素时比如 6 个,这时候列表最小容量 minCapacity 需要 10 + 6 = 16,新的容量 newCapacity 小于最小容量 minCapacity 则新数组容量取最小容量值 newCapacity = minCapacity。

对数组列表进行插入、删除操作时都需要对数组进行拷贝并重排序。所以如果能知道大概存储多少数据时,尽量初始化初始容量,提升性能。

List a = new ArrayList();a.add(11);a.add("aaa"); // 添加元素a.get(1); // 获取第二个元素值a.remove(1); // 删除第 2 个元素

1.2 LinkedList 双向链表

LinkedList 是双向链表,也即每个元素都有指向前后元素的指针。既然是链表那么顺序读取的效率非常高,而随机读取的效率较低。当随机获取一个 index位元素时,链表先比较 index 和链表长度 1/2 的大小,小于时从链表头部查找元素,大于时就从链表尾部查找元素。

LinkedList l =new LinkedList();l.add(1);l.add(2);l.getFirst(); // 获取第一个元素l.getLast(); // 获取最后一个元素l.remove(1); // 删除第 2 个元素

对比 ArrayList 如果随机读取数据较多时使用 ArrayList 性能高,插入删除较多时使用 LinkedList 性能高。

1.3 Vector 向量,线程安全的列表

与 ArrayList 一样也是通过数组实现的,不同的是 Vector 是线程安全的,也即同一时间下只能有一个线程访问 Vector,线程安全的同时带来了性能的耗损,所以一般都使用 ArrayList。Vector 的扩容也与 ArrayList 不同,可以设置扩容值,默认每次扩容原来的一倍。

Vector v = new Vector();v.add("aa");v.add("bb");v.get(1);v.remove(1);

1.4 Stack 栈,后进先出(LIFO)

Stack 继承自 Vector 所以也是数组实现的,线程安全的栈。因为 Stack 继承自 Vector 所以就拥有 Vector 中定义的方法,但作为栈数据类型,不建议使用 Vector 中与栈无关的方法,尽量只用 Stack 中的定义的栈相关方法,这样不会破坏栈数据类型。

Stack s = new Stack();s.push(1);s.push(2);s.pop(); // 抛出并删除首个元素s.peek(); // 返回首个元素值,不删除值

1.5 ArrayQueue 数组队列,先进后出(FIFO)

ArrayQueue 是数组实现的队列,从队尾加入数据,只能队头删除数据,可随机读取队列数据。

ArrayQueue q = new ArrayQueue(12);q.add(1);q.add(2);q.get(1);q.size();、q.remove(0);

2. Queue 队列,有序、可重复

继承自 Queue 的队列有:ArrayDeque、LinkedList、PriorityQueue。

2.1 ArrayDeque 数组实现的双端队列

ArrayDeque 是队列,但也可以作为栈使用,而且对比 Stack 更高效。作为双端队列那就可以在队列两端插入和删除元素。当追加元素超过容量限制时,则创建一个两边容量的新数组,并将原数组的内容拷贝到新数组中。

ArrayDeque d = new ArrayDeque();d.addFirst(11);d.addLast(22);d.pollFirst();d.pollLast(); // 返回并删除队尾元素d.peekLast(); // 返回但不删除队尾元素d.peekFirst();d.push(44);d.pop();

2.2 LinkedList 队列也是双向链表

上文 1.2 中已经提过,这里就不赘述了。推荐使用 ArrayDeque。

2.3 PriorityQueue 优先队列,数组实现的二叉树

PriorityQueue 是一个完全二叉树实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值)。

PriorityQueue q = new PriorityQueue();q.offer(1);q.offer(2);q.offer(3); // 插入元素q.peek(); // 查看顶端元素q.poll(); // 返回并删除顶端元素

详细介绍地址:PriorityQueue

3. Map 映射/字典,无序,键值对,键唯一

常用的 Map 实现有:HashMap、TreeMap、LinkedHashMap

3.1 HashMap 哈希映射/字典

HashMap 就是 key->value 的键值对数据,key 是唯一的,而且 key 和 value 都可以为 null。HashMap 和 HashTable 相似,HashTable 实现了线程同步,在Object超类解析章节中简单介绍过 HashTable 的数据存储方式。 HashMap 是个无序的字典,遍历时不保证元素顺序。HashMap 创建时默认会设置初始容量大小(默认16),和装载因子(默认 0.75,扩充容量的阀值),装载因子 = 已存入元素个数 / 总容量大小。当然这两个值也可以手动设置。 HashMap 的数据存储结构如下图:

HashMap 当插入一个数据时,先对 key 值做 hash,用得到的值与容器的大小 n 减 1 做 & 运算得到桶的位置,即:i = (n - 1) & hash,i 就是桶的位置。在桶中查找有无元素,没有直接插入,有则比较元素 key 值是否相同,相同用新值替换。

桶的位置计算为什么是 (n - 1) & hash?先看 hash 值的计算:

// hash() 函数返回一个整数static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}

hash() 函数对 key 取值后返回一个整数。又因为 HashMap 的容量 n 大小始终为 2 的幂(默认为 16),那么 n - 1 的二进制始终是最高位为 1,其它位为 0 的数,如:10...0,这个数与整数做 & 运算就得到 hash / n 的余数,余数的取值范围在 0 ~ n-1,很巧妙的设计。相关源码,这里截取了部分:

public class HashMap extends AbstractMap implements Map, Cloneable, Serializable {  // 构造函数 public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor;  // 扩容的阀值 this.threshold = tableSizeFor(initialCapacity); }  /** * 容器大小,返回 2 的幂 * Returns a power of two size for the given target capacity. */ static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; }  // 插入元素 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); }  /** * // 实际插入元素的方法 * Implements Map.put and related methods. * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node[] tab; Node p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) // resize 函数会设置扩容阀值 n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }  // 取 hash  static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } }

3.2 TreeMap 红黑树实现的 key->value 容器,可排序

红黑树是一种自平衡二叉查找树。 更多参考:

https://www.cnblogs.com/skywang12345/p/3245399.html

https://www.ibm.com/developerworks/cn/java/j-lo-tree/index.html

3.3 LinkedHashMap 链表映射/字典

LinkedHashMap 继承自 HashMap 所以具有 HashMap 的所有特性。同时又实现了双向链表的特性,保留了元素插入顺序。

LinkedHashMap l = new LinkedHashMap<>();l.put("a

java获取字典所有的key_JAVA脱水学习-java集合介绍,常用集合类相关推荐

  1. java获取字典所有的key_java字典,多层字典,斗地主发牌,实例展示

    在我们的日常工作与生活当中,java都有涉及到.它具有十分强大的功能,并且内容也极其丰富,使用频率也是很高的,所以大家对于java的学习热情也是十分积极的.今天就来为大家介绍java字典,多层字典,斗 ...

  2. Java架构师笔记-你必须掌握学习Java需要掌握哪些技能

    闲来无事,师长一向不(没)喜(有)欢(钱)凑热闹,倒不如趁着这时候复盘复盘.而写这篇文章的目的是想总结一下自己这么多年来使用java的一些心得体会,希望可以给大家一些经验,能让大家更好学习和使用Jav ...

  3. Java培训分享:零基础怎么学习Java?

    最近几年,有很多小伙伴都比较关注"零基础怎么学习Java?"这个问题,因为很多小伙伴都是从其他行业转型来学Java的,都很担心自己学不会,那么来看看下面的详细介绍吧. 零基础怎么学 ...

  4. java 获取 反射 方法 名_乐字节Java反射之一:反射概念与获取反射源头Class

    一.Java反射机制概念 "程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言",如Python, Ruby是动态语言:显然C++,Java,C#不是动态语言,但是JAV ...

  5. java第一阶段知识_坚持:学习Java后台的第一阶段,我学习了那些知识

    最近的计划是业余时间学习Java后台方面的知识,发现学习的过程中,要学的东西真多啊,让我一下子感觉很遥远.但是还好我制定了计划,自己选择的路,跪着也要走完!关于计划是<终于,我还是下决心学Jav ...

  6. java基础不好框架能学会吗_转行Java能学会吗?零基础学习Java的学习路线

    Java的跨平台性.通用性.安全性.高效性决定了这门语言在未来10年都会是最热门的语言之一.Java技术的安全性和平台移植性足够让他应用到不同的领域,它的工作需求足够大,现实一点来说即使Java濒临o ...

  7. java 并发编程视频教程_全面深入学习java并发编程,视频教程下载

    课程目标: * 颠覆一些你以为"正确"的认知,纠正其它同类视频的错误 * 100+ 张手绘图 & 流程图,帮助你形成正确的"多线程世界观" * 以知识点 ...

  8. 零基础可以学习java吗_零基础真的可以学习java吗?

    Java是一个比较抽象的开发语言,涉及知识点比较多,如果自学的话,可以按照五个阶段来学习,先学好基础知识,再逐步扩展,由易到难.要注意视频和书本内容相辅相成,切记不要只看视频而不忽略书本基础的知识要点 ...

  9. java 获取文件扩展名_如何在Java中获取文件扩展名

    java 获取文件扩展名 Sometimes while working with files, we need to process them differently based on their ...

最新文章

  1. 字节终面:CPU 是如何读写内存的?
  2. ibm xml专区中对XPATH的一个好文
  3. 给字母保密的c语言,C语言练习题
  4. python fabric上传文件夹_通过python的fabric包完成代码上传部署(简单版)
  5. java 算法 福尔摩斯的约会
  6. osql 登陆mysql_命令行登录mysql报Segmentation fault故障解决
  7. 分布式面试题(二):分布式Redis
  8. 计算机专业英语pdf词汇百度盘,计算机专业英语词汇词.pdf
  9. 学校官网首界面 html
  10. 国际贸易术语解释通则(DDU 未完税交货(……指定目的港))
  11. 亚马逊后台付款表(Custom Transaction)详解
  12. 计算机网络子网掩码计算题,计算机网络复习题(计算题)
  13. 华为6个月试用期经历
  14. 关于学习软件逆向分析意义的阐述
  15. Android12 apk安装失败 安装包异常 安装包大小显示1k
  16. Kubernetes 部署高可用集群(二进制,v1.18)下
  17. 广州坐标系转换大地2000_你好,怎么将经纬度坐标转换成大地2000坐标?
  18. 程序人生—谈安全测试的重要性
  19. 【头歌educoder】离散数学实训参考-第二章-关系-part1-关系基础
  20. unity3d 摄像机近地面清楚,远地面模糊

热门文章

  1. 超级有用的15个mysqlbinlog命令
  2. 二、源代码=程序集及程序集概念介绍
  3. RDD、DataFrame和DataSet
  4. Struts2之数据标签(二)
  5. [转载] 华中科技大学期刊分类办法
  6. DWR2学习笔记(一)
  7. 李维说他跳槽了,那我以后也不是Borland的Fans了?
  8. RecyclerView(四)设置分割线样式(Android 5.0 新特性)
  9. FLL - C++与VFP 双向混合编程
  10. 卷积神经网络之AlexNet