Java集合

目录

1、Java中集合的种类

2、Arrarlist与LinkedList的区别

3、Arrarlist与Vector的区别

4、list的遍历方式

5、HashMap

6、ConcurrentHashMap

7、HashTable

8、TreeMap(可排序)

9、LinkHashMap(记录插入顺序)

10、HashMap和Hashtable的区别

11、HashMap和HashSet的区别

12、HashSet如何检查重复

13、TreeMap和TreeSet的区别

14、泛型是什么,及其使用场景?


1、Java中集合的种类

主要包括Collection接口,Map接口以及Collection接口的三个子接口Set,List,Queue。

Java集合大致可以分为Set、List、Queue和Map四种体系,其中

Set代表无序、不可重复的集合;

List代表有序、重复的集合;list包括Arrarlist、Vector、LinkedList;

Map代表具有映射关系的集合,使用键值对来存储;

Java 5 又增加了Queue体系集合,代表一种队列集合实现。

Java集合就像一种容器,可以把多个对象(实际上是对象的引用,但习惯上都称对象)“丢进”该容器中。从Java 5 增加了泛型以后,Java集合可以记住容器中对象的数据类型,使得编码更加简洁、健壮。

2、Arrarlist与LinkedList的区别

1)都不能保证线程安全:两者都是不同步的,都不能保证线程安全;

2)底层数据结构:ArrayList底层使用的是Object数组;LinkedLIst底层是双向链表(JDK1.6之前微循环链表,1.7取消了循环)

3)插入和删除元素是否受元素位置的影响

4)是否支持快速随机访问

5)内存空格占用

3、Arrarlist与Vector的区别

Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的代码要在同步操作上消耗大量的时间,所以访问比ArrayList慢;

ArrayList不是同步的,所以在不需要保证线程安全时建议使用ArrayList。

4、list的遍历方式

1)实现了RandomAccess接口的list,优先选择普通for循环,其次foreach

2)为实现RandomAccess接口的list,优先选择foreach遍历(foreach循环底层也是通过iterator实现的),大size的数据,不要使用普通的for循环

5、HashMap

底层原理:JDK1.8之前是:数组和链表(链表散列)

JDK1.8之后是:数组、链表和红黑树

HashMap的结构:

java7: 数组+单向链表

1)capacity:当前数组容量,始终保持2的n次方,可以扩容,扩容后数组为当前的2倍;(始终保持2的N次方的原因是为了减少hash碰撞)

2)loadFactor:负载因子,默认为0.75;

3) threshold: 扩容的阀值,等于capacity*loadFactor。

java8: 数组+单向链表 +红黑树

查找的时间复杂度取决于链表的长度,为O(n);当链表的元素超过了8个以后,会将链表转换为红黑树,在这些位置查找时可以降低时间复杂度为O(logN)。

为什么设置的是8呢?

如果 hashCode 分布良好,也就是 hash 计算的结果离散好的话,那么红黑树这种形式是很少会被用到的,因为各个值都均匀分布,很少出现链表很长的情况。

在理想情况下,链表长度符合泊松分布,各个长度的命中概率依次递减,当长度为 8 的时候,概率仅为 0.00000006。这是一个小于千万分之一的概率,通常我们的 Map 里面是不会存储这么多的数据的,所以通常情况下,并不会发生从链表向红黑树的转换。

HashMap的存储方式与查询效率:

HashMap根据键的hashCode值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。

HashMap最多只允许一条记录的键为null,允许多条记录的值为null;

HashMap的线程安全性:

HashMap非线程安全,即任一时刻允许多个线程同时写HashMap,可能会导致数据的不一致。

保证线程安全:1)使用Collections的synchronizedMap方法是HashMap具有安全的能力;

2)使用ConcurrentHashMap。

6、ConcurrentHashMap

jdk1.7:

整个 ConcurrentHashMap 由一个个 Segment 组成,Segment 代表”部分“或”一段“的意思,所以很多地方都会将其描述为分段锁。

安全性:

ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。

并行度:

concurrencyLevel:并行级别、并发数、Segment 数,怎么翻译不重要,理解它。默认是 16,

也就是说 ConcurrentHashMap 有 16 个 Segments,所以理论上,这个时候,最多可以同时支持 16 个线程并发写,只要它们的操作分别分布在不同的 Segment 上。这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。再具体到每个 Segment 内部,其实每个 Segment 很像之前介绍的 HashMap,不过它要保证线程安全,所以处理起来要麻烦些。

jdk1.8:

采用CAS和Synchronized锁

7、HashTable

线程安全性:线程安全,任一时间只有一个线程能写HashTable;底层是hash表,使用了同步方法

并发性不如 ConcurrentHashMap,因为ConcurrentHashMap引入了分段锁。

Hashtable 不建议在新代码中使用,不需要线程安全的场合可以用 HashMap 替换,需要线程安全的场合可以用 ConcurrentHashMap 替换 。

8、TreeMap(可排序)

TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按健值的升序排序,也可以指定排序的比较器,当用Iterator遍历TreeMap时,得到的记录是排过序的。

9、LinkHashMap(记录插入顺序)

LinkedHashMap 是 HashMap 的一个子类,保存了记录的插入顺序,在用 Iterator 遍历

LinkedHashMap 时,先得到的记录肯定是先插入的,也可以在构造时带参数,按照访问次序排序

10、HashMap和Hashtable的区别

(1)HashMap是线程不安全,Hashtable是线程安全;

(2)效率:因为线程安全的问题,HashMap要比HashTable效率更高一点。

(3)HashMap中,null可以作为键值也可以value值,在HashTable中,不允许键值为null。

(4) 初始容量大小和每次扩充的容量大小都不同:不指定初始容量时:HashMap的初始容量W为16,每次扩充是2倍;Hashtable的初始容量是11,每次扩充是2n+1倍。 当指定初始容量时:Hashtable会直接使用给定的大小,而HashMap会将其扩充为2的幂次方大小;

(5)底层数据结构:1.8之后,HashTable在解决哈希冲突时有了较大的变化,当链表长度大于阈值8时,将链表转化为红黑树,用来减少搜索时间;HashTable没有这样的机制。

11、HashMap和HashSet的区别

HashSet的底层就是Hashmap来实现的;

HashMap实现的是Map接口,存储键值对,put添加元素,使用key计算Hashode;HashSet实现的是Set接口,存储对象,add添加元素,使用成员对象计算HashCode值,对于两个对象来说hashcoad可能相同,所以用equels方法来判断对象的相等性;

12、HashSet如何检查重复

当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功。

13、TreeMap和TreeSet的区别

TreeSet

1.TreeSet)是使用二又树的原理对新add0的对象按照指定的顺序排序(升序、降序),每增加一个对象都会进行排序,将对象插入的二又树指定的位置。

2.Integer和String对象都可以进行默认的TreeSet排序,而自定义类的对象是不可以的,自己定义的类必须实现Comparable接口,并且覆写相应的compareTo)函数,才可以正常使用。

3.在覆写compare0函数时,要返回相应的值才能使TreeSet 按照一定的规则来排序

4.比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。

TreeMap

TreeMap实现SortedMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用lterator 遍历TreeMap时,得到的记录是排过序的。

如果使用排序的映射,建议使用TreeMap。

在使用TreeMap时,key必须实现Comparable接口或者在构造TreeMap传入自定义的Comparator,否则会在运行时抛出java.lang.ClassCastException类型的异常。

14、泛型是什么,及其使用场景?

泛型就是一种未知的类,将未知的类型声明在集合、对象上,泛型的默认类型为Object。

泛型只能定义引用数据类型,而不能使用基本数据类型

泛型类、泛型方法、泛型接口、泛型通配符

例如:作用在类上时( public class Animal { E pet; } ) , 泛型跟在类后边,可以指定用了泛型的类内部的 pet 的类型。

作用在对象上时( Animal str = new Animal(); ) , 泛型跟在类后边 , 使得对象类的的 pet 属性为 Dog类型。

作用在方法上时( public Animal getPet(){ return E ; } ), 如在类上没有声明泛型时,必须在返回值和访问修饰符之间声明。

作为方法入参时( public void setPet(E pet){ this.pet = pet ; } ), 如在类上没有声明泛型时,必须在返回值和访问修饰符之间声明。

  • 28
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值