2 容器

1. Java 容器都有哪些?

答:

|----Collection接口:单列集合,用来存储一个一个的对象
*         |----List接口:存储序的、可重复的数据。  -->“动态”数组
*              |----ArrayList:作为List接口的主要实现类;线程不安全的,效率高;底层使用Object[] elementData存储
*              |----LinkedList:对于频繁的插入、删除操作,使用此类效率比ArrayList高;底层使用双向链表存储
*              |----Vector:作为List接口的古老实现类;线程安全的,效率低;底层使用Object[] elementData存储
*
*         |----Set接口:存储无序的、不可重复的数据-->高中讲的“集合”
*              |----HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值
*                  |----LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历。 在添加数据的同时,每个数据还维护了两个引用,记录此数据前一      个数据和后一个数据。对于频繁的遍历操作,LinkedHashSet效率高于HashSet。
*              |----TreeSet:可以照添加对象的指定属性,进行排序。

|----Map:双列数据,存储key-value对的数据   ---类似于高中的函数:y = f(x)
*       |----HashMap:作为Map的主要实现类;线程不安全的,效率高;存储null的key和value
*              |----LinkedHashMap:保证在遍历map元素时,可以照添加的顺序实现遍历。
*                    原因:在原的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。
*                    对于频繁的遍历操作,此类执行效率高于HashMap。
*       |----TreeMap:保证照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序,底层使用红黑树。
*       |----Hashtable:作为古老的实现类;线程安全的,效率低;不能存储null的key和value
*              |----Properties:常用来处理配置文件。key和value都是String类型

补充:在查询和增删操作相同的场景下,选LinkedList还是ArrayList?

答:此场景时间差不多,决定效率高低在于占用的空间,Linked内存不连续,不需要考虑扩容问题,所以占用空间更少,不产生浪费。(感觉此处还要考虑查询多与少的情况以及增删操作多与少的情况)
2. Collection Collections 有什么区别?

  • Collection 是一个接口,它是 Set、List 等容器的父接口;
  • Collections 是一个工具类, 提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全 化等等。

3. ListSetMap 之间的区别是什么?

答:List、SetMap的区别主要体现在两个方面:元素是否有序、是否允许元素重复。三者之间的区别,如下表:

4.ArrayList、Vector、LinkedList的异同?

同:三个类都实现了List接口,存储数据的特点相同:存储有序的、可重复的数据。

异:

  • ArrayList:jdk1.2时有的,是List接口的主要实现类;底层创建了长度为10的数组(JDK7),扩容时为原来的1.5倍,同时需要将原有数组中的数据复制到新的数组中;线程不安全,但是效率高。
  • Vector:jdk1.0时有的,是List接口的古老实现类;底层创建了长度为10的数组,扩容时为原来的2倍;Vector使用了synchronized来实现线程同步,是线程安全的,但是效率低。
  • LinkedList:jdk1.2时有的,底层使用双向链表存储;线程不安全,对于频繁的插入、删除操作,使用LinkedList效率低ArrayList高。

补充:对于ArrayList,jdk7时,上来就先创建了长度为10的数组,类似于单例模式中饿汉式;jdk8时,底层数组初始化为{},并没创建长度为10的数组,而是等第一次调用add()时,底层才创建了长度为10的数组,,类似于单例模式中的懒汉式,节省了内存。

5. ArrayList 和 LinkedList 的区别是什么?

  • 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
  • 随机访问效率:ArrayList LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
  • 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。

综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList

6.ArrayList 和 Vector 的区别是什么?

  • 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
  • 性能:ArrayList 在性能方面要优于 Vector
  • 扩容:ArrayList Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%

7.Array 和 ArrayList 有何区别?

  • Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
  • Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
  • Array 内置方法没有 ArrayList 多,比如 addAllremoveAlliteration 等方法只有 ArrayList 有。

8.如何实现数组和 List 之间的转换?

  • 数组转 List:使用 Arrays. asList(array) 进行转换。
  • List 转数组:使用 List 自带的 toArray() 方法。

9.在 Queue poll() remove()有什么区别?

  • 相同点:都是返回第一个元素,并在队列中删除返回的对象。
  • 不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。

10.HashSet、LinkedHashSet、TreeSet的区别?

  • HashSet:作为Set接口的主要实现类;线程不安全的;可以存储null值;其底层使用HashMap实现的。
  • LinkedHashSet:作为HashSet的子类;遍历其内部数据时,可以按照添加的顺序遍历。 在添加数据的同时,每个数据还维护了两个引用,记录此数据前一个数据和后一个数据。对于频繁的遍历操作,LinkedHashSet效率高于HashSet;其底层LinkedHashMap。
  • TreeSet:可以照添加对象的指定属性,进行排序。其底层实现基于TreeMap用红黑树存储数据。和 TreeMap 相似,TreeSet 可以使用 Comparable 接口或 Comparator 接口对元素排序。

11.HashSet 的实现原理?

答:HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

添加元素时:我们向HashSet中添加元素a,首先调用元素a所在类的hashCode()方法,计算元素a的哈希值,此哈希值接着通过某种算法计算出在HashSet底层数组中的存放位置(即为:索引位置,判断数组此位置上是否已经元素:
      如果此位置上没其他元素,则元素a添加成功。 --->情况1
      如果此位置上其他元素b(或以链表形式存在的多个元素,则比较元素a与元素b的hash值:
             如果hash值不相同,则元素a添加成功。--->情况2
             如果hash值相同,进而需要调用元素a所在类的equals()方法:
                    equals()返回true,元素a添加失败
                    equals()返回false,则元素a添加成功。--->情况3

对于添加成功的情况2和情况3而言:元素a 与已经存在指定索引位置上数据以链表的方式存储。
jdk 7 :元素a放到数组中,指向原来的元素。
jdk 8 :原来的元素在数组中,指向元素a
总结:七上八下

12.HashMap、LinkedHashMap、TreeMap、Hashtable的区别?

  • HashMap:jdk1.2时有,作为Map的主要实现类; 是散列映射,通过散列函数计算键对应的存储位置,因此可以快速地完成放置键值对、删除键值对、根据键获得值的操作;线程不安全的,效率高;可以存储null的key和value。底层创建了长度是16的一维数组Entry[] table,扩容为原来容量的2倍,并将原的数据复制过来。
  • LinkedHashMap:jdk1.4时有,保证在遍历map元素时,可以照添加的顺序实现遍历。 原因:在原的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。   对于频繁的遍历操作,此类执行效率高于HashMap。
  • TreeMap:jdk1.2时有,保证照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序, 是有序映射,键可以使用Comparable接口或Comparator 接口排序。底层使用红黑树通过红黑树维护映射的有序性。由于要维护映射的有序性,因此 TreeMap 的各项操作的平均效率低于 HashMap,但是TreeMap 可以按照顺序获得键值对。
  • Hashtable:jdk1.0时有,作为古老的实现类,是散列表;线程安全的,效率低;不能存储null的key和value。

补充:JDK 1.8 之前的 HashMap 的底层通过数组和链表实现,如果出现冲突则通过拉链法解决冲突。JDK 1.8 在解决冲突时的实现有较大变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树,以减少搜索时间。

13. HashMap 和 Hashtable 有什么区别?

  • 存储:HashMap 运行 key value null,而 Hashtable 不允许。
  • 线程安全:Hashtable 的大多数方法用关键字 synchronized 修饰,因此 Hashtable  是线程安全的, HashMap 是非线程安全的。在不需要保证线程安全的情况下,HashMap 的效率高于 Hashtable。
  • 推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用ConcurrentHashMap 替代。

14.Hashtable和ConcurrentHashMap的区别?

  • Hashtable:①底层:数组+链表     ②key和value不能为null      ③线程安全,Hashtable的synchronized是针对整张hash表的,即每次锁住整张表让线程独占,效率低    ④初始size为11,扩容:newsize = oldsize * 2 + 1
  • ConcurrentHashMap:①底层:分段的数组+链表实现      ②通过把整个map分成N个segment,可以提供相同的线程安全,效率提升。通过使用锁分段技术,允许多个修改操作并发进行

补充:

锁分段技术:首先将数据分成一段一段的存储,然后给每一段配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。

15.如何决定使用 HashMap 还是 TreeMap

答:对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 HashMap 的插入会更快,但如果你要对一个 key 集合进行有序的遍历,那 TreeMap 是更好的选择。

16.TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比 较元素?

答:TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素 的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap 要求存放的键 值对映射的键必须实现 Comparable 接口从而根据键对元素进行排序。

Collections 工具类的 sort 方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现 Comparable 接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但 是要求传入第二个参数,参数是 Comparator 接口的子类型(需要重写 compare 方法实现元 素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算 法,也是对回调模式的应用(Java 中对函数式编程的支持)。

17.HashMap 的实现原理?

答:HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。

HashMap map = new HashMap():
*      在实例化以后,底层创建了长度是16的一维数组Entry[] table。
*      ...可能已经执行过多次put...
*      map.put(key1,value1):
*      首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置。
*      如果此位置上的数据为空,此时的key1-value1添加成功。 ----情况1
*      如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
*              如果key1的哈希值与已经存在的数据的哈希值都不相同,此时key1-value1添加成功。----情况2
*              如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals(key2)方法,比较:
*                      如果equals()返回false:此时key1-value1添加成功。----情况3
*                      如果equals()返回true:使用value1替换value2。
*
*      补充:关于情况2和情况3:此时key1-value1和原来的数据以链表的方式存储。
*     在不断的添加过程中,会涉及到扩容问题,当超出临界值(且要存放的位置非空)时,扩容。默认的扩容方式:扩容为原来容量的2倍,并将原的数据复制过来。

18.HashSet和TreeSet的区别有哪些?

  • HashSet 的底层实现基于 HashMap,元素是无序的,通过方法 hashCode 和 equals 保证元素没有重复。
  • TreeSet 的底层实现基于 TreeMap,元素是有序的,通过 Comparable 接口或 Comparator 接口保证元素没有重复。

19.哪些集合类是线程安全的?

答:VectorHashtableStack 都是线程安全的,而像 HashMap 则是非线程安全的,不过在 JDK 1.5 之后随着 Java. util. concurrent 并发包的出现,它们也有了自己对应的线程安全类,比如 HashMap 对应的线程安全类就是 ConcurrentHashMap

20.Iterator 和 ListIterator 有什么区别?

  • Iterator 可以遍历 Set List 集合,而 ListIterator 只能遍历 List
  • Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
  • ListIterator Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值