当前位置 : 主页 > 编程语言 > java >

Java集合基础

来源:互联网 收集:自由互联 发布时间:2023-09-06
1、遍历List集合的方式1、for 循环遍历:基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。 2、迭代器遍历:Iterator 是面向对象

1、遍历List集合的方式 1、for 循环遍历:基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。

2、迭代器遍历:Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。

3、foreach 循环:foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。

数组和 List 之间的转换 数组转 List:使用 Arrays. asList(array) 进行转换。 List 转数组:使用 List 自带的 toArray() 方法。 ArrayList 和 LinkedList 的区别 1、数据结构:ArrayList基于数组实现,内存是连续的;LinkedList基于双向链表实现,内存不连续

2、随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList需要移动指针从前往后依次查找。

3、增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。

4、内存空间:ArrayList 需要预留额外的存储空间;LinkedList需要储存前后指针

hashMap 1.7 和 hashMap 1.8 的区别

ArrayList 和 Vector 的区别 这两个类都实现了 List 接口,他们都是有序集合

线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。 性能:ArrayList 在性能方面要优于 Vector。 扩容: Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。 多线程场景下使用 ArrayList 1、通过 Collections 的 synchronizedList 方法将 ArrayList 转换成线程安全的容器后再使用

2、使用线程安全的 CopyOnWriteArrayList 代替线程不安全的 ArrayList。

3、为list.add()方法加锁

4、为list.add()方法加锁

List 和 Set 的区别 1、List , Set 都是继承自Collection 接口

2、List :有序可重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。

3、Set:无序不可以存储重复,只允许存入一个null元素性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。

4、List 支持for循环和迭代器的遍历;set只能用迭代,因为他无序,无法用下标来取得想要的值。

HashSet 的实现原理 HashSet 是基于 HashMap 实现的,HashSet的值存放于HashMap的key上,HashMap的value统一为present,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

HashSet如何检查重复

set 继承于 Collection 接口,是一个不允许出现重复元素,并且无序的集合.

HashSet 是基于 HashMap 实现的,底层采用 HashMap 来保存元素

元素的哈希值是通过元素的 hashcode 方法 来获取的, HashSet 首先判断两个元素的哈希值,如果哈希值一样,接着会比较 equals 方法 如果 equls 结果为 true ,HashSet 就视为同一个元素。如果 equals 为 false 就不是同一个元素。

HashSet与HashMap的区别

HashMap、HashTable 1、HashMap是现场不安全的;HashTable是线程安全的

2、HashMap的K只能有一个为null,V可以有多个;HashTable的K和V不能为null

3、HashMap的初始容量是16,按2倍进行扩容;HashTable初始容量是11,按2n+1进行扩容

4、HashMap是储存映射关系;HashTable是储存对象

ConcurrentHashMap、HashTable 底层数据结构:

ConcurrentHashMap:jdk1.7(分段数组+链表),jdk8(数组+链表/红黑树)

HashTable:数组+链表

实现线程安全的方式:

ConcurrentHashMap:

jdk7:使用分段锁,对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分的桶

jdk8:采用Synchronized + CAS机制 保证了线程的安全,锁的仅是链表或红黑树的首节点,降低了锁粒度,大大提高并发度。

HashTable:使用synchronized修改put和get方法

comparable 、 comparator 所属的包:

comparable:java.lang包

comparator:java.util 包

排序的方法:

comparable:compareTo(Object obj)方法

comparator:compare(Object obj1, Object obj2)方法

Collection 、 Collections java.util.Collection 是一个集合接口(集合类的一个顶级接口)。

它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。 Collections则是集合类的一个工具类/帮助类。

其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。 HashMap 线程不安全;key只能有一个null,value可以有多个null

数据结构:

JDK 7 中,HashMap 由“数组+链表”组成,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的。

在 JDK 8 中,HashMap 由“数组+链表+红黑树”组成。链表过长,会严重影响 HashMap 的性能,而红黑树搜索的时间复杂度是 O(logn),而链表是糟糕的 O(n)。因此,JDK 8 对数据结构做了进一步的优化,引入了红黑树,链表和红黑树在达到一定条件会进行转换:

当链表超过 8 且数据总量超过 64 时会转红黑树。 将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。 JDK 8 中 HashMap 的结构示意图:

为什么链表改为红黑树的阈值是 8?

因为泊松分布(是根据概率统计而选择的)

解决hash冲突的办法有哪些?HashMap用的哪种?

散列法、再哈希法、拉链法(HashMap)

为什么在解决 hash 冲突的时候,不直接用红黑树?而选择先用链表,再转红黑树?

因为红黑树需要进行左旋,右旋,变色这些操作来保持平衡,而单链表不需要。

当元素小于 8 个的时候,此时做查询操作,链表结构已经能保证查询性能。

因此,如果一开始就用红黑树结构,元素太少,新增效率又比较慢,无疑这是浪费性能的。

HashMap默认加载因子是多少?为什么?

加载因子是表示Hsah表中元素的填满的程度;

加载因子越大,填满的元素越多,空间利用率越高,但冲突的机会加大了,查找的成本越高。

因此0.75是冲突概率与空间利用率的最佳值

HashMap 中 key 的存储索引是怎么计算的?

首先根据key的值计算出hashcode的值,然后根据hashcode计算出hash值,最后通过

hash &(length-1)计算得到存储的位置。

为什么 hash 值要与length-1相与?

hash &(length-1)等价于 hash %(length-1);但&比%的效率高

HashMap数组的长度为什么是 2 的幂次方?

2 的 N 次幂有助于减少碰撞的几率。如果 length 为2的幂次方,则 length-1 转化为二进制必定是11111……的形式,在与h的二进制与操作效率会非常的快,而且空间不浪费。

如果用户传入的容量不是 2 的 n 次方,会自动地将传入的容量转换为 2 的 n 次方。

最终数组容量=比构造方法中传递的数大的最小2的n次幂。 例如:传递10,容量为16,传递28,容量为32

HashMap 的put方法流程?

1、首先根据 key 的值计算 hash 值,找到该元素在数组中存储的下标;

2、如果数组是空的,则调用 resize 进行初始化(数组长度16);

3、如果没有哈希冲突直接放在对应的数组下标里;

4、如果冲突了,且 key 已经存在,就覆盖掉 value;

5、如果冲突后,发现该节点是红黑树,就将这个节点挂在树上;

6、如果冲突后是链表,判断该链表是否大于 8 ,如果大于 8 并且数组容量小于 64,就进行扩容;如果链表节点大于 8 并且数组的容量大于 64,则将这个结构转换为红黑树;否则,在链表的尾端插入键值对,若 key 存在,就覆盖掉 value。

一般用什么作为HashMap的key?

一般用Integer、String 这种不可变类当作 HashMap 的 key,String 最为常见。

因为获取对象的时候要用到 equals() 和 hashCode() 方法,那么键对象正确的重写这两个方法是非常重要的

构造方法:

无参构造方法:默认加载因子为0.75,并不创建数组,而是在首次进行put时,创建数组并且长度(桶的个数)为16

指定容量的构造函数:此时加载因子为0.75

指定容量和加载因子的构造函数:

传递Map的构造函数:

resize()实现过程:

判断旧数组的容量是否大于0,从而确定数组是否初始化过

否:进行初始化

调用无参构造器:使用默认的容量和加载因子。

调用有参构造器:使用构造器中传递的容量(比构造方法中传递的数大的最小2的n次幂)

是:进行扩容,扩容的倍数为2

先生成新的数组,遍历旧数组中每个桶中链表或红黑树上的元素,并重新计算下标,在放到对应的新数组中

遍历方式:

迭代器中循环删除数据安全,其他的都不安全

迭代器(Iterator)方式:

EntrySet:遍历的效率高,因为只进行了一次循环

KeySet:效率低,需要循环2次

For Each 方式:

EntrySet:遍历的效率高,因为只进行了一次循环

KeySet:效率低,需要循环2次

Lambda 表达式:jdk8新增

Stream流 :jdk8新增

LinkedHashMap 在HashMap的基础上增加了一条双向链(因此插入和访问的顺序是一致的)

是线程不安全的

key只能有一个为null,value可以有多个为null。

HashTable 数组+链表组成的,数组是 Hashtable 的主体,链表则是主要为了解决哈希冲突而存在的

是线程安全的(内部使用synchronized修饰,锁的是整张表,粒度较大)

key和value都不能为空

ConcurrentHashMap 是线程安全的集合;key和value都不可以为null;对于get方法而言,不需要进行加锁,因为对元素和指针都使用volatile进行修饰,保证了可见性。

不同点 1.7 1.8 锁粒度 基于segment 基于entry节点 线程安全实现 采用Segment(分段锁)对所有的桶进行分段,锁的是多个桶。 采用Synchronized + CAS机制;锁的仅是链表或红黑树的首节点 储存数据结构 数组+链表 数组+链表+红黑树 size方法安全保证 靠Segment加锁方式实现 靠CAS和Volatile或synchronized方式实现

【本文由:盐城网页开发公司 http://www.1234xp.com/yancheng.html 复制请保留原URL】
上一篇:设计模式-原型模式
下一篇:没有了
网友评论