当前位置:网站首页 > 技术博客 > 正文

java集合大全



大家好,又见面了,我是你们的朋友全栈君。

Java集合详解(超详细)

集合、数组都是对多个数据进行存储操作的结构,简称Java容器。 说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)

一旦初始化以后,其长度就确定了。 数组一旦定义好,其元素的类型也就确定了。我们也就只能操作指定类型的数据了。

1.一旦初始化以后,其长度就不可修改。 2.数组中提供的方法非常限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。 3.获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用 4.数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足。

Java集合可分为Collection和Map两种体系

其中:

代码实例:

注意:

注意:

代码实例:

鉴于Java中数组用来存储数据的局限性,我们通常使用List替代数组 List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引。 List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。 JDK AP中List接口的实现类常用的有:ArrayList、LinkedList和 Vector.

ArrayList的三个构造方法:

(1)ArrayList()构造一个初始容量为 10 的空列表。

(2)ArrayList(int initialCapacity)构造一个具有指定初始容量的空列表。

(3)ArrayList(Collection<? extends E> c)构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。

Set接口是Collection的子接口,set接口没有提供额外的方法 Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加操作失败。(多用于过滤操作,去掉重复数据) Set判断两个对象是否相同不是使用==运算符,而是根据equals()方法

HashSet使用哈希表实现的,元素是无序的。添加、删除操作时间复杂度都是O(1)。 TreeSet内部结构是一个树结构(红黑树),元素是有序的,添加、删除操作时间复杂度为O(log(n)),并且提供了first(), last(), headSet(), tailSet()等方法来处理有序集合。 LinkedHashSet是介于HashSet 和 TreeSet之间,内部是一个双向链表结构,所以它的插入是有序的,时间复杂度是O(1)。

以HashSet为例说明:

概述:

元素添加过程:(难点)

我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置),判断数组此位置上是否已经有元素:

对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。 JDK 7.0 和JDK 8.0 元素添加的区别:

与HashSet集合相比,TreeSet还提供了几个额外方法:

Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null; Object first():返回集合中的第一个元素; Object last():返回集合中的最后一个元素; Object lower(Object e):返回指定元素之前的元素。 Object higher(Object e):返回指定元素之后的元素。 SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾; SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成; SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成;

说明:

执行结果:会抛出一个异常:java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 原因:向TreeSet中添加的数据,要求是相同类的对象

执行结果:java.lang.ClassCastException,出现了类型转换异常 原因:在于我们需要告诉TreeSet如何来进行比较元素,如果不指定,就会抛出这个异常

解决:

指定比较的规则,在自定义类(Person)中实现Comparable接口,并重写接口中的compareTo方法

说明:

注意:

代码实例:

说明:

代码实例:

添加、删除、修改、查询方法:

元视图操作的方法:(Map的遍历)

元素添加过程简要说明:

HashMap的底层实现原理?以jdk7为例说明: 1.HashMap map = new HashMap(): 2.在实例化以后,底层创建了长度是16的一维数组Entry[] table。

3.map.put(key1,value1):(可能已经执行过多次put) 4.首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。 1)如果此位置上的数据为空,此时的key1-value1添加成功。 —-情况1 2)如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值: ①如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。—-情况2 ②如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较: 如果equals()返回false:此时key1-value1添加成功。—-情况3 如果equals()返回true:使用value1替换value2。 补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。 HashMap的扩容:(jdk7) 在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的2倍,并将原有的数据复制过来。 当HashMap中的元素越来越多的时候,hash冲突的几率也就越来越高,因为数组的长度是固定的。所以为了提高查询的效率,就要对 HashMap的数组进行扩容,而在HashMap数组扩容之后,原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是 resize。 HashMap扩容时机:(jdk7) 当HashMap中的元素个数超过数组大小(数组总大小 length,不是数组中个数)* loadFactor时,就会进行数组扩容,loadFactor的默认值(DEFAULT_LOAD_ FACTOR)为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小(DEFAULT INITIAL CAPACITY)为16,那么当 HashMap中元素个数超过16 * 0.75=12(这个值就是代码中的 threshold值,也叫做临界值)的时候,就把数组的大小扩展为2 * 16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知 HashMap中元素的个数,那么预设元素的个数能够有效的提高HashMap的性能。

HashMap在JDK 8.0底层实现原理:

HashMap添加元素的过程:(jdk8) 当实例化一个HashMap时,会初始化 initialCapacity和loadFactor,在put第一对映射关系时,系统会创建一个长度为 initialCapacity的Node数组,这个长度在哈希表中被称为容量(Capacity),在这个数组中可以存放元素的位置我们称之为“桶”( bucket),每个bucket都有自己的索引,系统可以根据索引快速的查找bucket中的元素。 每个 bucket中存储一个元素,即一个Node对象,但每一个Noe对象可以带个引用变量next,用于指向下一个元素,因此,在一个桶中,就有可能生成一个Node链。也可能是一个一个 TreeNode对象,每一个Tree node对象可以有两个叶子结点left和right,因此,在一个桶中,就有可能生成一个TreeNode树。而新添加的元素作为链表的last,或树的叶子结点。 HashMap的扩容机制:(jdk8) 当HashMapl中的其中一个链的对象个数没有达到8个和JDK 7.0以前的扩容方式一样。 当HashMapl中的其中一个链的对象个数如果达到了8个,此时如果 capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成 Tree Node类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。 jdk8 相较于jdk7在底层实现方面的不同: 1.new HashMap():底层没有创建一个长度为16的数组 2. jdk 8底层的数组是:Node[],而非Entry[] 3. 首次调用put()方法时,底层创建长度为16的数组 4. jdk7底层结构只有:数组+链表。jdk8中底层结构:数组+链表+红黑树。 1)形成链表时,七上八下(jdk7:新的元素指向旧的元素。jdk8:旧的元素指向新的元素) 2)当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 64时,此时此索引位置上的所数据改为使用红黑树存储。(方便查找)

HashMap底层典型属性的说明: DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16 DEFAULT_LOAD_FACTOR:HashMap的默认加载因子:0.75 threshold:扩容的临界值,= 容量*填充因子:16 * 0.75 => 12 TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:JDK 8.0引入 MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量:64

LinkedHashMap底层使用的结构与HashMap相同,因为LinkedHashMap继承于HashMap. 区别就在于:LinkedHashMap内部提供了Entry,替换HashMap中的Node. 与LinkedhashSet类似,LinkedHashMap可以维护Map的迭代顺序:迭代顺序与Key-value对的插入顺序一致

1.TreeMap存储Key-Value对时,需要根据key-value对进行排序。TreeMap可以保证所有的 Key-Value对处于有序状态。 2.TreeSet底层使用红黑树结构存储数据 3.TreeMap的Key的排序:

代码示例:

Hashtable的介绍:

Hashtable是个古老的Map实现类,JDK1.0就提供了。不同于 HashMap,Hashtable是线程安全的. Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用 与HashMap.不同,Hashtable不允许使用null作为key和value. 与HashMap一样,Hashtable也不能保证其中Key-value对的顺序. Hashtable判断两个key相等、两个value相等的标准,与HashMap-致.

Properties类是Hashtable的子类,该对象用于处理属性文件

由于属性文件里的key、value都是字符串类型,所以Properties里的key和value都是字符串类型 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法

代码实例:

出现中文乱码的解决办法:

使用Classloader加载src目录下的配置文件

1. 作用:

Collections是一个操作Set、List和Map等集合的工具类 Collections中提供了一系列静态的方法对集合元素进行排序、査询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法

代码实例:

ArrayList和 Linkedlist的异同: 二者都线程不安全,相比线程安全的 Vector,ArrayList执行效率高。 此外,ArrayList是实现了基于动态数组的数据结构,Linkedlist基于链表的数据结构。对于随机访问get和set,ArrayList觉得优于Linkedlist,因为Linkedlist要移动指针。对于新增和删除操作add(特指插入)和 remove,Linkedlist比较占优势,因为 ArrayList要移动数据。 ArrayList和 Vector的区别: Vector和ArrayList几乎是完全相同的,唯一的区别在于Vector是同步类(synchronized),属于强同步类。因此开销就比 ArrayList要大,访问要慢。正常情况下,大多数的Java程序员使用ArrayList而不是Vector,因为同步完全可以由程序员自己来控制。Vector每次扩容请求其大小的2倍空间,而ArrayList是1.5倍。Vector还有一个子类Stack.

负载因子的大小决定了HashMap的数据密度。 负载因子越大密度越大,发生碰撞的几率越高,数组中的链表越容易长,造成査询或插入时的比较次数增多,性能会下降 负载因子越小,就越容易触发扩容,数据密度也越小,意味着发生碰撞的几率越小,数组中的链表也就越短,查询和插入时比较的次数也越小,性能会更高。但是会浪费一定的内容空间。而且经常扩容也会影响性能,建议初始化预设大一点的空间 按照其他语言的参考及研究经验,会考虑将负载因子设置为0.7~0.75,此时平均检索长度接近于常数。

好的博客: Java集合类(四)—TreeSet

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/141715.html原文链接:https://javaforall.cn

版权声明


相关文章:

  • 什么算高并发2025-05-06 11:01:04
  • autoconf命令2025-05-06 11:01:04
  • 异步fifo设计思路2025-05-06 11:01:04
  • 代码对比合并工具2025-05-06 11:01:04
  • left join select2025-05-06 11:01:04
  • 请问安全测试是什么?2025-05-06 11:01:04
  • win系统找不到策略组2025-05-06 11:01:04
  • linux查看文件权限修改记录2025-05-06 11:01:04
  • c语言引用类型变量2025-05-06 11:01:04
  • 二阶低通滤波器波形图2025-05-06 11:01:04