Java--collection与map

来源:互联网 发布:环形网络业务保护方式 编辑:程序博客网 时间:2024/05/22 08:24



1. Set、map、list区别

1.1 集合树继承图解

集合类型主要有3种:set、list和map

集合树继承图解

常用的集合类的关系如下: 
|——Collection接口 
|——|——List接口 
|————|——ArrayList类 
|————|——LinkedList类 
|————|——Vector类 
|——|——Set接口 
|————|——HashSet类 
|————|——SortedSet接口 
|——————|——TreeSet类

|——Map 
|——|——HashMap类 
|——|——HashTable类 
|——|——SortedMap接口 
|————|——TreeMap类

1.2 Collection

Collection是最基本的集合接口。 
Java SDK 不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。 
不论Collection的实际类型如何,它都支持一个iterator()方法返回一个迭代器,对元素进行遍历。 
由Collection接口派生的两个接口是List和Set。

(1)List : 有序列表,允许存放重复的元素 
实现类: 
1)
ArrayList数组实现,需要一块连续的存储空间,封装了一个允许动态分配的Object[]、随机访问查询快,增删慢,不同步,线程不安全,轻量级; 
2)LinkedList双向列表实现,增删快,随机访问查询稍慢;,还提供了双端队列和栈等功能。
3)Vector数组实现,和ArrayList一样允许动态分配的Object[],都有一个初始化容量大小,当超出时需要扩容,默认情况下Vector扩容到原来的2被,ArrayList为1.5被。 同步,线程安全,重量级。 Vector很古老从Java1.0开始就有,那时还没有集合框架,虽然是线程安全的,但性能很差,不推荐使用,往往在多线程情况下考虑Collections工具类将ArrayList编程线程安全的。Vector有个子类Stack描述栈这种数据结构,很古老性能差,虽线程安全但是不推荐使用,可以使用Queue或者LinkedList实现Stack

4)固定长度的List:  Arrays.asList()方法,这个List不是ArrayList的实例,而是Arrays有个内部类ArrayList的实例。 程序只能遍历集合中元素,不可增删改

List性能分析: 遍历List集合,对于底层是数组实现的ArrayList、Vector应该使用随机访问(get)方法来遍历比较好,对于LinkedList采用迭代器来遍历性能更好。如果涉及集合操作包括大量的插入删除操作,应使用LinkedList,因为ArrayList、Vector可能需要经常重新分配数组大小。


(2)Set:无序,不允许存放重复的集合 
实现类: 
1)
HashSet: 使用成员对象来计算hashCode值,对于两个对象来说hashCode可能相同,这时会调用equals()||==方法来判断对象的相等性,如果两个对象不同的话,那么返回false, 对象允许插入。所以在存储对象之前,要先确保对象重写了equals和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有存储相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。如果你对hashCode()和equals()不了解的话,可以参考Java 中正确使用 hashCode 和 equals 方法 ,线程不安全的,无序的,集合元素值可以为null,获取速度最快。
2)LinkedHashSet:HashSet的子类,存储的数据是按照插入顺序的 ,hashcode决定存储位置,链表来维护内部顺序
3)TreeSet:使用元素的自然顺序对元素进行排序,或者根据创建set时提供的Comparator进行排序,如果在创建set时没有指定元素排序的比较器,元素又没有可比较性,则会报错,这时元素必须实现Comparable接口并重写compareTo()方法红黑树实现的;判断两个对象是否相等:通过compareTo比较看是否返回0,

各种Set性能分析:

HashSet性能总是比TreeSet性能好,尤其在添加、查询上,因为TreeSet底层需要用红黑树来维持顺序,所以需要一个保持自然顺序的Set序列时用TreeSet。介于两者之间的是HashSet的子类LinkedHashSet,hashcode决定存储位置,链表来维持插入顺序。

(1)Hash算法的价值在于速度,首先计算hashCode确定元素存储的位置,从而快速的进行索引查找。当然数组是所有存储一维元素里最快的,但是它必须是连续的而且数组长度是固定的,所以不适合。而HashSet先通过hashCode计算出存储位置,从而可以增加hashSet的长度。

List和Set:与Set的iterator()方法不同,List还增加了 一个listIterator方法,该方法返回一个ListIterator对象,相比于Iterator的hasNext,next方法,该接口还增加了 hasPrevious,previous,add方法,可以向前迭代,也可以在指定位置插入元素。

Iterator:使用Iterator对集合迭代时,并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量对集合中元素的值没有影响,也就是当Iterator访问Collection集合时,集合中的元素不能被改变,只能调用iterator的remove方法删除。当然ListIterator里可以add

3 Map 键值对,key不可以重复,Map包括一个内部类Entry来封装k-v对。Entry包括方法  entrySet()、getKey()、getValue、setValue

(1)HashMap:key允许null键和值,最多一个key=null的键值对;线程不安全 
(2)Hashtable:线程安全;不允许null键和值。 
(3)Properties:key和value都是String类型,用来读配置文件; 
(4)TreeMap:红黑树,对key进行排序的Map;key要实现Comparable接口或在new一个TreeMap的时候指定比较器。 
(5)LinkedHashMap:存储的数据是有序的。

判断两个key是否相等:Hashtable和HashMap采用hashCode+equals,判断两个value是否相等:equals即可。所以注意重写这两种方法。

1.4 两个工具类Arrays和Collections 
Arrays包含用来操作数据(比如排序和搜索)的各种方法。 
Collections主要提供了在collections上进行操作的静态方法。

2. HashMap(很重要,必看)

2.1 什么时候会使用HashMap?他有什么特点? 
是基于Map接口的实现,存储键值对时;它可以接受null的键值,是非同步的,HashMap存储着Entry(hash, key, value, next)对象。

2.2 工作原理 
(1)HashMap是以Entry[]数组实现的哈希桶数组。 
(2)插入元素时,先根据key的hashCode计算hash值, 再根据hash值计算得到这个元素在数组中的bucket位置(n-1&hash)。 
如果该位置上已经存放有其他元素了,那么在这个位置上的元素将以单向链表的形式存放,新加入的放在链头,最先加入的放在链尾,数组中存储的是最后插入的元素; 
如果该位置上没有元素,就直接将该元素放到此数组中的该位置上。 
(3)查找对象时,也是根据key的hashCode计算hash值,再根据hash值计算得到这个元素的bucket位置,然后遍历桶里所有元素,逐个比较(equals方法)其key值确认键值对。

2.3 当Entry数量达到桶数量的75%(很多文章说使用的桶数量达到75%,但看代码不是),会成倍扩容桶数量, 
并重新分配原来所有的Entry,所以这里也最好有个预估值。

2.4 为什么String, Integer这样的wrapper类适合作为键? 
String,Integer这样的wrapper类是final类型的,具有不可变性,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。 
不可变形是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashCode的话,那么就不能从HashMap中找到你想要的对象。

2.5 HashMap的遍历 
第一种:

  Map map = new HashMap();  Iterator iter = map.entrySet().iterator();  while (iter.hasNext()) {  Map.Entry entry = (Map.Entry) iter.next();  Object key = entry.getKey();  Object val = entry.getValue();  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  效率高,以后一定要使用此种方式! 第二种:   
Map map = new HashMap();  Iterator iter = map.keySet().iterator();  while (iter.hasNext()) {  Object key = iter.next();  Object val = map.get(key);  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

为什么第一种比第二种方法效率更高呢? 
HashMap这两种遍历方法是分别对keyset及entryset来进行遍历,但是对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,即键值对,所以就快了。

3. Arraylist、LinkedList、Vector区别

参考 比较ArrayList、LinkedList、Vector 
这三者都实现了List接口,所有使用方式也很相似,主要区别在于因为实现方式的不同,所以对不同操作具有不同的效率。 
(1)ArrayList:是一个可改变大小的数组,当更多的元素加入到ArrayList中时,其大小将会动态地增长,内部的元素可以通过get与set方法进行访问,因为ArrayList本质上就是一个数组。 
(2)LinkedList:是一个双链表,在删除和添加元素时具有比ArrayList更好的性能,但是在get和set方法弱于ArrayList。当然这些对比都是数据量很大或者操作很频繁的情况的才有意义。 
(3)Vector和ArrayList类似,但ArrayList是线程不安全的,Vector是线程安全的。如果你的程序本身是线程安全的(没有在多个线程之间共享的对象),那么使用ArrayList是更好的选择。 
Vector和ArrayList在更多元素添加进来时都会请求更大的空间。Vector每次请求其大小的两倍,ArrayList则是增长0.5倍。 
注意:默认情况下ArrayList的初始容量非常小,所以如果可以预估数量的话,分配一个较大的初始值是比较好的。这样可以减少调整大小的开销。 
简单来说,LinkedList更适用于: 
1)没有大规模的随机读取 
2)大量的增加/删除操作

4. HashSet、LinkedHashSet、TreeSet区别

HashSet:不能保证元素的排列顺序,顺序有可能发生变化。当向HashSet添加一个元素时,会调用对象的hashCode()方法返回哈希值,再对返回的哈希值进行计算得到元素的存储位置,如果该位置上没有元素的话,则直接将元素插入到该位置上;如果该位置上已有元素的话,则遍历该位置上的链表元素,调用equals()方法来比较是否已存在相等的元素,如果有返回true的话,则该 
元素是重复元素,不能插入,否则,则可以成功插入。

LinkedHashSet:同样是根据hashCode()来得到元素的存储位置和equals()方法来判断元素是否是重复元素。但是它同时使用链表维护元素的次序。也就是遍历该集合时,LinkedHashSet将会以元素的添加顺序访问集合的元素。 
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

TreeSet:是采用树结构实现(红黑树算法)。元素是按顺序进行排列。可以按照元素的自然顺序排序或者指定比较器。TreeSet判断两个对象不相等的方式是通过CompareTo方法比较没有返回0。

5. HashMap、TreeMap、LinkedHashMap区别

HashMap:基于哈希表实现,是无序的。 
TreeMap:基于红黑树实现,按key排序。 
LinkedHashMap:保存了插入顺序。 
HashTable:是同步的,与HashMap类似。

6. 熟悉Java集合类的框架图

7. HashMap、ArrayList、StringBuffer、String等源码的熟悉


1. Set、map、list区别

1.1 集合树继承图解

集合类型主要有3种:set、list和map

集合树继承图解

常用的集合类的关系如下: 
|——Collection接口 
|——|——List接口 
|————|——ArrayList类 
|————|——LinkedList类 
|————|——Vector类 
|——|——Set接口 
|————|——HashSet类 
|————|——SortedSet接口 
|——————|——TreeSet类

|——Map 
|——|——HashMap类 
|——|——HashTable类 
|——|——SortedMap接口 
|————|——TreeMap类

1.2 Collection

Collection是最基本的集合接口。 
Java SDK 不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。 
不论Collection的实际类型如何,它都支持一个iterator()方法返回一个迭代器,对元素进行遍历。 
由Collection接口派生的两个接口是List和Set。

(1)List : 有序列表,允许存放重复的元素 
实现类: 
1)
ArrayList数组实现,需要一块连续的存储空间,封装了一个允许动态分配的Object[]、随机访问查询快,增删慢,不同步,线程不安全,轻量级; 
2)LinkedList:链表实现,增删快,随机访问查询稍慢;,还提供了双端队列和栈等功能。
3)Vector数组实现,和ArrayList一样允许动态分配的Object[], 同步,线程安全,重量级。 Vector很古老从Java1.0开始就有,那时还没有集合框架,虽然是线程安全的,但性能很差,不推荐使用,往往在多线程情况下考虑Collections工具类将ArrayList编程线程安全的。Vector有个子类Stack描述栈这种数据结构,很古老性能差,虽线程安全但是不推荐使用,可以使用Queue或者LinkedList实现Stack

4)固定长度的List:  Arrays.asList()方法,这个List不是ArrayList的实例,而是Arrays有个内部类ArrayList的实例。 程序只能遍历集合中元素,不可增删改

List性能分析: 遍历List集合,对于底层是数组实现的ArrayList、Vector应该使用随机访问(get)方法来遍历比较好,对于LinkedList采用迭代器来遍历性能更好。如果涉及集合操作包括大量的插入删除操作,应使用LinkedList,因为ArrayList、Vector可能需要经常重新分配数组大小。


(2)Set:无序,不允许存放重复的集合 
实现类: 
1)
HashSet: 使用成员对象来计算hashCode值,对于两个对象来说hashCode可能相同,这时会调用equals()||==方法来判断对象的相等性,如果两个对象不同的话,那么返回false, 对象允许插入。所以在存储对象之前,要先确保对象重写了equals和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有存储相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。如果你对hashCode()和equals()不了解的话,可以参考Java 中正确使用 hashCode 和 equals 方法 ,线程不安全的,无序的,集合元素值可以为null,获取速度最快。
2)LinkedHashSet:HashSet的子类,存储的数据是按照插入顺序的 ,hashcode决定存储位置,链表来维护内部顺序
3)TreeSet:使用元素的自然顺序对元素进行排序,或者根据创建set时提供的Comparator进行排序,如果在创建set时没有指定元素排序的比较器,元素又没有可比较性,则会报错,这时元素必须实现Comparable接口并重写compareTo()方法红黑树实现的;判断两个对象是否相等:通过compareTo比较看是否返回0,

各种Set性能分析:

HashSet性能总是比TreeSet性能好,尤其在添加、查询上,因为TreeSet底层需要用红黑树来维持顺序,所以需要一个保持自然顺序的Set序列时用TreeSet。介于两者之间的是HashSet的子类LinkedHashSet,hashcode决定存储位置,链表来维持插入顺序。


List和Set:与Set的iterator()方法不同,List还增加了 一个listIterator方法,该方法返回一个ListIterator对象,相比于Iterator的hasNext,next方法,该接口还增加了 hasPrevious,previous,add方法,可以向前迭代,也可以在指定位置插入元素。

Iterator:使用Iterator对集合迭代时,并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量对集合中元素的值没有影响,也就是当Iterator访问Collection集合时,集合中的元素不能被改变,只能调用iterator的remove方法删除。当然ListIterator里可以add

3 Map 键值对,key不可以重复,

(1)HashMap:key允许null键和值;线程不安全 
(2)HashTable:线程安全;不允许null键和值。 
(3)Properties:key和value都是String类型,用来读配置文件; 
(4)TreeMap:对key进行排序的Map;key要实现Comparable接口或在new一个TreeMap的时候指定比较器。 
(5)LinkedHashMap:存储的数据是有序的。

1.4 两个工具类Arrays和Collections 
Arrays包含用来操作数据(比如排序和搜索)的各种方法。 
Collections主要提供了在collections上进行操作的静态方法。

2. HashMap(很重要,必看)

参考Java HashMap工作原理及实现 
HashMap笔试面试题汇总解析

2.1 什么时候会使用HashMap?他有什么特点? 
是基于Map接口的实现,存储键值对时;它可以接受null的键值,是非同步的,HashMap存储着Entry(hash, key, value, next)对象。

2.2 工作原理 
(1)HashMap是以Entry[]数组实现的哈希桶数组。 
(2)插入元素时,先根据key的hashCode计算hash值, 再根据hash值计算得到这个元素在数组中的bucket位置(n-1&hash)。 
如果该位置上已经存放有其他元素了,那么在这个位置上的元素将以单向链表的形式存放,新加入的放在链头,最先加入的放在链尾,数组中存储的是最后插入的元素; 
如果该位置上没有元素,就直接将该元素放到此数组中的该位置上。 
(3)查找对象时,也是根据key的hashCode计算hash值,再根据hash值计算得到这个元素的bucket位置,然后遍历桶里所有元素,逐个比较(equals方法)其key值确认键值对。

2.3 当Entry数量达到桶数量的75%(很多文章说使用的桶数量达到75%,但看代码不是),会成倍扩容桶数量, 
并重新分配原来所有的Entry,所以这里也最好有个预估值。

2.4 为什么String, Integer这样的wrapper类适合作为键? 
String,Integer这样的wrapper类是final类型的,具有不可变性,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。 
不可变形是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashCode的话,那么就不能从HashMap中找到你想要的对象。

2.5 HashMap的遍历 
第一种:

  Map map = new HashMap();  Iterator iter = map.entrySet().iterator();  while (iter.hasNext()) {  Map.Entry entry = (Map.Entry) iter.next();  Object key = entry.getKey();  Object val = entry.getValue();  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  效率高,以后一定要使用此种方式! 第二种:   
Map map = new HashMap();  Iterator iter = map.keySet().iterator();  while (iter.hasNext()) {  Object key = iter.next();  Object val = map.get(key);  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

为什么第一种比第二种方法效率更高呢? 
HashMap这两种遍历方法是分别对keyset及entryset来进行遍历,但是对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,即键值对,所以就快了。

3. Arraylist、LinkedList、Vector区别

参考 比较ArrayList、LinkedList、Vector 
这三者都实现了List接口,所有使用方式也很相似,主要区别在于因为实现方式的不同,所以对不同操作具有不同的效率。 
(1)ArrayList:是一个可改变大小的数组,当更多的元素加入到ArrayList中时,其大小将会动态地增长,内部的元素可以通过get与set方法进行访问,因为ArrayList本质上就是一个数组。 
(2)LinkedList:是一个双链表,在删除和添加元素时具有比ArrayList更好的性能,但是在get和set方法弱于ArrayList。当然这些对比都是数据量很大或者操作很频繁的情况的才有意义。 
(3)Vector和ArrayList类似,但ArrayList是线程不安全的,Vector是线程安全的。如果你的程序本身是线程安全的(没有在多个线程之间共享的对象),那么使用ArrayList是更好的选择。 
Vector和ArrayList在更多元素添加进来时都会请求更大的空间。Vector每次请求其大小的两倍,ArrayList则是增长0.5倍。 
注意:默认情况下ArrayList的初始容量非常小,所以如果可以预估数量的话,分配一个较大的初始值是比较好的。这样可以减少调整大小的开销。 
简单来说,LinkedList更适用于: 
1)没有大规模的随机读取 
2)大量的增加/删除操作

4. HashSet、LinkedHashSet、TreeSet区别

HashSet:不能保证元素的排列顺序,顺序有可能发生变化。当向HashSet添加一个元素时,会调用对象的hashCode()方法返回哈希值,再对返回的哈希值进行计算得到元素的存储位置,如果该位置上没有元素的话,则直接将元素插入到该位置上;如果该位置上已有元素的话,则遍历该位置上的链表元素,调用equals()方法来比较是否已存在相等的元素,如果有返回true的话,则该 
元素是重复元素,不能插入,否则,则可以成功插入。

LinkedHashSet:同样是根据hashCode()来得到元素的存储位置和equals()方法来判断元素是否是重复元素。但是它同时使用链表维护元素的次序。也就是遍历该集合时,LinkedHashSet将会以元素的添加顺序访问集合的元素。 
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

TreeSet:是采用树结构实现(红黑树算法)。元素是按顺序进行排列。可以按照元素的自然顺序排序或者指定比较器。TreeSet判断两个对象不相等的方式是通过CompareTo方法比较没有返回0。

5. HashMap、TreeMap、LinkedHashMap区别

HashMap:基于哈希表实现,是无序的。 
TreeMap:基于红黑树实现,按key排序。 
LinkedHashMap:保存了插入顺序。 
HashTable:是同步的,与HashMap类似。

6. 熟悉Java集合类的框架图

7. HashMap、ArrayList、StringBuffer、String等源码的熟悉

1. Set、map、list区别

1.1 集合树继承图解

集合类型主要有3种:set、list和map

集合树继承图解

常用的集合类的关系如下: 
|——Collection接口 
|——|——List接口 
|————|——ArrayList类 
|————|——LinkedList类 
|————|——Vector类 
|——|——Set接口 
|————|——HashSet类 
|————|——SortedSet接口 
|——————|——TreeSet类

|——Map 
|——|——HashMap类 
|——|——HashTable类 
|——|——SortedMap接口 
|————|——TreeMap类

1.2 Collection

Collection是最基本的集合接口。 
Java SDK 不提供直接继承自Collection的类,Java SDK提供的类都是继承自Collection的“子接口”如List和Set。 
不论Collection的实际类型如何,它都支持一个iterator()方法返回一个迭代器,对元素进行遍历。 
由Collection接口派生的两个接口是List和Set。

(1)List : 有序列表,允许存放重复的元素 
实现类: 
1)
ArrayList数组实现,需要一块连续的存储空间,封装了一个允许动态分配的Object[]、随机访问查询快,增删慢,不同步,线程不安全,轻量级; 
2)LinkedList:链表实现,增删快,随机访问查询稍慢;,还提供了双端队列和栈等功能。
3)Vector数组实现,和ArrayList一样允许动态分配的Object[], 同步,线程安全,重量级。 Vector很古老从Java1.0开始就有,那时还没有集合框架,虽然是线程安全的,但性能很差,不推荐使用,往往在多线程情况下考虑Collections工具类将ArrayList编程线程安全的。Vector有个子类Stack描述栈这种数据结构,很古老性能差,虽线程安全但是不推荐使用,可以使用Queue或者LinkedList实现Stack

4)固定长度的List:  Arrays.asList()方法,这个List不是ArrayList的实例,而是Arrays有个内部类ArrayList的实例。 程序只能遍历集合中元素,不可增删改

List性能分析: 遍历List集合,对于底层是数组实现的ArrayList、Vector应该使用随机访问(get)方法来遍历比较好,对于LinkedList采用迭代器来遍历性能更好。如果涉及集合操作包括大量的插入删除操作,应使用LinkedList,因为ArrayList、Vector可能需要经常重新分配数组大小。


(2)Set:无序,不允许存放重复的集合 
实现类: 
1)
HashSet: 使用成员对象来计算hashCode值,对于两个对象来说hashCode可能相同,这时会调用equals()||==方法来判断对象的相等性,如果两个对象不同的话,那么返回false, 对象允许插入。所以在存储对象之前,要先确保对象重写了equals和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有存储相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。如果你对hashCode()和equals()不了解的话,可以参考Java 中正确使用 hashCode 和 equals 方法 ,线程不安全的,无序的,集合元素值可以为null,获取速度最快。
2)LinkedHashSet:HashSet的子类,存储的数据是按照插入顺序的 ,hashcode决定存储位置,链表来维护内部顺序
3)TreeSet:使用元素的自然顺序对元素进行排序,或者根据创建set时提供的Comparator进行排序,如果在创建set时没有指定元素排序的比较器,元素又没有可比较性,则会报错,这时元素必须实现Comparable接口并重写compareTo()方法红黑树实现的;判断两个对象是否相等:通过compareTo比较看是否返回0,

各种Set性能分析:

HashSet性能总是比TreeSet性能好,尤其在添加、查询上,因为TreeSet底层需要用红黑树来维持顺序,所以需要一个保持自然顺序的Set序列时用TreeSet。介于两者之间的是HashSet的子类LinkedHashSet,hashcode决定存储位置,链表来维持插入顺序。

(1)Hash算法的价值在于速度,首先计算hashCode确定元素存储的位置,从而快速的进行索引查找。当然数组是所有存储一维元素里最快的,但是它必须是连续的而且数组长度是固定的,所以不适合。而HashSet先通过hashCode计算出存储位置,从而可以增加hashSet的长度。

List和Set:与Set的iterator()方法不同,List还增加了 一个listIterator方法,该方法返回一个ListIterator对象,相比于Iterator的hasNext,next方法,该接口还增加了 hasPrevious,previous,add方法,可以向前迭代,也可以在指定位置插入元素。

Iterator:使用Iterator对集合迭代时,并不是把集合元素本身传给了迭代变量,而是把集合元素的值传给了迭代变量,所以修改迭代变量对集合中元素的值没有影响,也就是当Iterator访问Collection集合时,集合中的元素不能被改变,只能调用iterator的remove方法删除。当然ListIterator里可以add

3 Map 键值对,key不可以重复,Map包括一个内部类Entry来封装k-v对。Entry包括方法  entrySet()、getKey()、getValue、setValue

(1)HashMap:key允许null键和值,最多一个key=null的键值对;线程不安全 
(2)Hashtable:线程安全;不允许null键和值。 
(3)Properties:key和value都是String类型,用来读配置文件; 
(4)TreeMap:对key进行排序的Map;key要实现Comparable接口或在new一个TreeMap的时候指定比较器。 
(5)LinkedHashMap:存储的数据是有序的。

判断两个key是否相等:Hashtable和HashMap采用hashCode+equals,判断两个value是否相等:equals即可。所以注意重写这两种方法。

1.4 两个工具类Arrays和Collections 
Arrays包含用来操作数据(比如排序和搜索)的各种方法。 
Collections主要提供了在collections上进行操作的静态方法。

2. HashMap(很重要,必看)

参考Java HashMap工作原理及实现 
HashMap笔试面试题汇总解析

2.1 什么时候会使用HashMap?他有什么特点? 
是基于Map接口的实现,存储键值对时;它可以接受null的键值,是非同步的,HashMap存储着Entry(hash, key, value, next)对象。

2.2 工作原理 
(1)HashMap是以Entry[]数组实现的哈希桶数组。 
(2)插入元素时,先根据key的hashCode计算hash值, 再根据hash值计算得到这个元素在数组中的bucket位置(n-1&hash)。 
如果该位置上已经存放有其他元素了,那么在这个位置上的元素将以单向链表的形式存放,新加入的放在链头,最先加入的放在链尾,数组中存储的是最后插入的元素; 
如果该位置上没有元素,就直接将该元素放到此数组中的该位置上。 
(3)查找对象时,也是根据key的hashCode计算hash值,再根据hash值计算得到这个元素的bucket位置,然后遍历桶里所有元素,逐个比较(equals方法)其key值确认键值对。

2.3 当Entry数量达到桶数量的75%(很多文章说使用的桶数量达到75%,但看代码不是),会成倍扩容桶数量, 
并重新分配原来所有的Entry,所以这里也最好有个预估值。

2.4 为什么String, Integer这样的wrapper类适合作为键? 
String,Integer这样的wrapper类是final类型的,具有不可变性,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。 
不可变形是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashCode的话,那么就不能从HashMap中找到你想要的对象。

2.5 HashMap的遍历 
第一种:

  Map map = new HashMap();  Iterator iter = map.entrySet().iterator();  while (iter.hasNext()) {  Map.Entry entry = (Map.Entry) iter.next();  Object key = entry.getKey();  Object val = entry.getValue();  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  效率高,以后一定要使用此种方式! 第二种:   
Map map = new HashMap();  Iterator iter = map.keySet().iterator();  while (iter.hasNext()) {  Object key = iter.next();  Object val = map.get(key);  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

为什么第一种比第二种方法效率更高呢? 
HashMap这两种遍历方法是分别对keyset及entryset来进行遍历,但是对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,即键值对,所以就快了。

3. Arraylist、LinkedList、Vector区别

参考 比较ArrayList、LinkedList、Vector 
这三者都实现了List接口,所有使用方式也很相似,主要区别在于因为实现方式的不同,所以对不同操作具有不同的效率。 
(1)ArrayList:是一个可改变大小的数组,当更多的元素加入到ArrayList中时,其大小将会动态地增长,内部的元素可以通过get与set方法进行访问,因为ArrayList本质上就是一个数组。 
(2)LinkedList:是一个双链表,在删除和添加元素时具有比ArrayList更好的性能,但是在get和set方法弱于ArrayList。当然这些对比都是数据量很大或者操作很频繁的情况的才有意义。 
(3)Vector和ArrayList类似,但ArrayList是线程不安全的,Vector是线程安全的。如果你的程序本身是线程安全的(没有在多个线程之间共享的对象),那么使用ArrayList是更好的选择。 
Vector和ArrayList在更多元素添加进来时都会请求更大的空间。Vector每次请求其大小的两倍,ArrayList则是增长0.5倍。 
注意:默认情况下ArrayList的初始容量非常小,所以如果可以预估数量的话,分配一个较大的初始值是比较好的。这样可以减少调整大小的开销。 
简单来说,LinkedList更适用于: 
1)没有大规模的随机读取 
2)大量的增加/删除操作

4. HashSet、LinkedHashSet、TreeSet区别

HashSet:不能保证元素的排列顺序,顺序有可能发生变化。当向HashSet添加一个元素时,会调用对象的hashCode()方法返回哈希值,再对返回的哈希值进行计算得到元素的存储位置,如果该位置上没有元素的话,则直接将元素插入到该位置上;如果该位置上已有元素的话,则遍历该位置上的链表元素,调用equals()方法来比较是否已存在相等的元素,如果有返回true的话,则该 
元素是重复元素,不能插入,否则,则可以成功插入。

LinkedHashSet:同样是根据hashCode()来得到元素的存储位置和equals()方法来判断元素是否是重复元素。但是它同时使用链表维护元素的次序。也就是遍历该集合时,LinkedHashSet将会以元素的添加顺序访问集合的元素。 
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

TreeSet:是采用树结构实现(红黑树算法)。元素是按顺序进行排列。可以按照元素的自然顺序排序或者指定比较器。TreeSet判断两个对象不相等的方式是通过CompareTo方法比较没有返回0。

5. HashMap、TreeMap、LinkedHashMap区别

HashMap:基于哈希表实现,是无序的。 
TreeMap:基于红黑树实现,按key排序。 
LinkedHashMap:保存了插入顺序。 
HashTable:是同步的,与HashMap类似。

6. 熟悉Java集合类的框架图

7. HashMap、ArrayList、StringBuffer、String等源码的熟悉

0 0