JavaSE基础(7)——Java的集合

1、List三个子类的特点

ArrayList底层结构是数组,底层查询快,增删慢。

LinkedList底层结构是链表型的,增删快,查询慢。

Vector底层 结构是数组,线程安全的,增删 慢,查询慢

2、List和Map、Set的区别

(1)结构特点 

List和 Set 是存储单列数据的集合, Map 是存储键和值这样的双列数据的集合 ,List 中存储的数据是有顺序,并且允许重复; Map 中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的, Set 中存储的数据是无序的,且不允许有重复,但元素在集合中的位置由元素的 hashcode 决定,位置是固定的(Set 集合根据 hashcode 来进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说set 中的元素还是无序的)

(2)实现类

List接口有三个实现类( LinkedList :基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢; ArrayList :基于数组实现,非线程安全的,效率高,便于索引,但不便于插入删除; Vector :基于数组实现,线程安全的,效率低)。

Map接口有三个实现类( HashMap :基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null键; HashTable :线程安全,低效,不支持 null 值和 null 键; LinkedHashMap :是 HashMap 的一个子类,保存了记录的插入顺序; SortMap 接口: TreeMap ,能够把它保存的记录根据键排序,默认是键值的升序排序)。

Set接口有两个实现类( HashSet :底层是由 HashMap 实现,不允许集合中有重复的值,使用该方式时需要重写 equals() 和hashCode() 方法; LinkedHashSet :继承于 HashSet ,同时又基于 LinkedHashMap 来进行实现,底层使用的是 LinkedHashMp )。

(3)区别

List集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get(i) 方法来获取集合中的元素; Map 中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复; Set 集合 中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如 TreeSet 类,可以按照默认顺序,也可以通过实现 Java.util.Comparator 接口来自定义排序方式。

3、HashMap和HashTable 有什么区别

HashMap是线程不安全的 ,HashMap 是一个接口 是 Map 的一个子接口 是将键映射到值得对象 不允许键值重复,允许空键和空值
由于非线程安全 ,HashMap 的效率要较 HashTable 的效率高一些

HashTable 是线程安全的一个集合 不允许 null 值作为一个 key 值或者 Value 值
HashTable是 sychronize, 多个线程访问时不需要自己为它的方法实现同步,而 HashMap 在被多个线程访问的时候需要自己为它的方法实现同步

4、数组和链表分别比较适合用于什么场景,为什么?

(1)数组和链表简介

在计算机中要对给定的数据集进行若干处理,首要任务是把数据集的一部分(当数据量非常大时,可能只能一部分一部分地读取数据到内存中来处理)或全部存储到内存中,然后再对内存中的数据进行各种 处理。

例如,对于数据集S{1 2 3 4 5 6}6},要求 S 中元素的和,首先要把数据存储到内存中,然后再将内存中的数据相加。

当内存空间中有足够大的连续空间时,可以把数据连续的存放在内存中,各种编程语言中的数组一般都是按这种方式存储的(也可能有例外),如图 1 b );当内存中只有一些离散的可用空间时,想连续存储数据就非常困难了,这时能想到的一种解决方式是移动内存中的数据,把离散的空间聚集成连续的一块大空间,如图 1 c )所示,这样做当然也可以,但是这种情况因为可能要移动别人的数据,所以会存在一些困难,移动的过程 中也有可能会把一些别人的重要数据给丢失。另外一种,不影响别人的数据存储方式是把数据集中的数据分开离散地存储到这些不连续空间中,如图( d )。这时为了能把数据集中的所有数据联系起来,需要在前一块数据的存储空间中记录下一块数据的地址,这样只要知道第一块内存空间的地址就能环环相扣地把数据集整体联系在一起了。 C/C++ 中用指针实现的链表就是这种存储形式。

JavaSE基础(7)——Java的集合_第1张图片

由上可知,内存中的存储形式可以分为连续存储和离散存储两种。因此,数据的物理存储结构就有连续存储和离散存储两种,它们对应了我们通常所说的数组和链表

(2)数组和链表的区别

数组是将元素在内存中连续存储的;它的优点:因为数据是连续存储的,内存地址连续,所以在查找数据的时候效率比较高;它的缺点:在存储之前,我们需要申请一块连续的内存空间,并且在编译的时候就必须确定好它的空间的大小。在运行的时候空间的大小是无法随着你的需要进行增加和减少而改变的,当数据两比较大的时候,有可能会出现越界的情况,数据比较小的时候,又有可能会浪费掉内存空间。在改变数据个数时,增加、插入、删除数据效率比较低。

链表是动态申请内存空间,不需要像数组需要提前申请好内存的大小,链表只需在用的时候申请就可以,根据需要来动态申请或者删除内存空间,对于数据增加和删除以及插入比数组灵活。还有就是链表中数据在内存 中可以在任意的位置,通过应用来关联数据(就是通过存在元素的指针来联系)

(3)数组和链表使用场景

数组应用场景:数据比较少;经常做的运算是按序号访问数据元素;数组更容易实现,任何高级语言都支持;构建的线性表较稳定。
链表应用场景:对线性表的长度或者规模难以估计;频繁做插入删除操作;构建动态性比较强的线性表。

5、Java中ArrayList和LinkedList区别

ArrayList和 Vector 使用 了数组的实现,可以认为 ArrayList 或者 Vector 封装了对内部数组的操作,比如向数组中添加,删除,插入新的元素或者数据的扩展和重定向。
LinkedList使用了循环双向链表数据结构。与基于数组 的 ArrayList 相比,这是两种截然不同的实现技术,这也决定了它们将适用于完全不同的工作场景。

LinkedList链表由一系列表项连接而成。一个表项总是包含 3 个部分:元素内容,前驱表和后驱表,如图所示:

JavaSE基础(7)——Java的集合_第2张图片

在下图展示了一个包含3 个元素的 LinkedList 的各个表项间的连接关系。在 JDK 的实现中,无论 LikedList 是否为空,链表内部都有一个 header 表项,它既表示链表的开始,也表示链表的结尾。表项 header 的后驱表项便是链表中第一个元素,表项 header 的前驱表项便是链表中最后一个元素。

JavaSE基础(7)——Java的集合_第3张图片

6、要对集合更新操作时, ArrayList 和 LinkedList 哪个更适合?

ArrayList是实现了基于动态数组的 数据结构,LinkedList 基于链表的数据结构。
如果集合数据是对于集合随机访问 get 和 set ,ArrayList 绝对优于 LinkedList ,因为 LinkedList 要移动指针。
 如果集合数据是对于集合新增和删除操作 add 和 remove, LinedList 比较占优势,因为 ArrayList 要移动数据。

ArrayList和 LinkedList 是两个集合类,用于存储一系列的对象引用 ( references)。例如我们可以用 ArrayList 来存储一系列的 String 或者 Integer 。那 么 ArrayList 和 LinkedList 在性能上有什么差别呢?什么时候应该用 Arra yList什么时候又该用 LinkedList 呢?

(1)时间复杂度

首先一点关键的是, ArrayList 的内部实现是基于基础的对象数组的,因此,它使用 get 方法访问列表中的任意一个元素时 (random access),它的速度要比 LinkedList 快。 LinkedList 中的 get 方法是按照顺序从列表的一端开始检查,直到另外一端。对 LinkedList 而言,访问列表中的某个指定元素没有更快的方法了。

(2)空间复杂度

在 LinkedList 中有一个私有的内部类,定义如下:

private static class Entry{
     Object element;
     Entry next;
     Entry previous;
}

每个Entry 对象 reference 列表 中的一个元素,同时还有在 LinkedList 中它的上一个元素和下一个元素。一个有 1000 个元素的 LinkedList 对象将有 1000 个链接在一起 的 Entry 对象,每个对象都对应于列表中的一个元素。这样的话,在一个 LinkedList 结构中将有一个很大的空间开销,因为它要存储这 1000 个 Entity 对象的相关信息。

ArrayList 使用一个内置的数组来存 储元素,这个数组的起始容量是 10. 当数组需要增长时,新的容量按如下公式获得:新容量 旧容量 *3)/2+1 ,也就是说每一次容量大概会增长 50% 。 这就意味着,如果你有一个包含大量元素的 ArrayList 对象,那么最终将有很大的空间会被浪费掉,这个浪费是由 ArrayList 的工作方式本身造成 的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个 ArrayList 将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过 trimToSize 方法在 ArrayList 分配完毕之后去掉浪 费掉的空间。

(3)总结

ArrayList 和 LinkedList 在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下:
对 ArrayList 和 LinkedList 而言,在列表末尾增加一个元素所花的 开销都是固定的。对 ArrayList 而言,主要是在内部数组中增加一项,指向所添加的元素,偶 尔可能会导致对数组重新进行分配;而对 LinkedList 而言,这个开销是统一的,分配一个内部 Entry 对象。
在 ArrayList 的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在 LinkedList 的中间插入或删除一个元素的开销是固定的。
LinkedList 不支持高效的随机元素访问。
ArrayList 的空间浪费主要体现在在 list 列表的结尾预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗相当的空间

可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间 并且需要随机地访问其中的元素时 使用ArrayList会提供比好的性能;当你的操作是在一列数据的前面或中间添加或删除数据 并且按照顺序访问其中的元素时 就应该使用 LinkedList 了。

7、Collection 和 Map 的集成体系

Collection:
JavaSE基础(7)——Java的集合_第4张图片

Map:

JavaSE基础(7)——Java的集合_第5张图片

 

你可能感兴趣的:(Java技术)