JAVA 集合
2016年3月换工作,面试图灵机器人的过程中被问到HashMap, Hashtable 和 TreeMap的区别,居然被问住了,虽然工作四年了,在解决具体问题时貌似还没遇到过翻不过去的坑。但是最近的面试也深刻的认识到基础知识该忘的忘,该不知道的不知道,究其原因,都是之前懒得或不屑总结。
就这个问题本身,回来学习后回答如下:
从两个方面分析
一,是否可以使用null,作为key或者value
HashMap,可以使用null值作为key或者value,当null作为key时,由于HashMap的key,不可重复,所以最多可以存入一个key为null的Entry。而当null作为value时,可以有多个value为null的Entry。
Hashtable,不可以将null值作为key或value,当向Hashtable中放入null值时,会报NullPointExecption。
以上两种,在内部实现时,均依靠key值使用Hash原理进行元素存储。他们均是Map接口的典型实现类。
TreeMap,是SortedMap接口的实现类,而SortedMap继承自Map接口。TreeMap内部维护以Key为排序依据的红黑树数据结构,当null作为key时,会NullPointException,但是当null用作value时可以有多个value为null的Entry。
验证代码如下:
import java.util.HashMap; import java.util.Hashtable; import java.util.TreeMap; public class MapNullTest { public static void main(String[] args) { //1. HashMap null test HashMap<String, String> hashMap = new HashMap<>(); hashMap.put(null, null); hashMap.put(null, null); hashMap.put("a", null); hashMap.put("b", null); System.out.println("hashMap: " + hashMap); //2. HashTable null test Hashtable<String, String> hashTable = new Hashtable(); try { hashTable.put(null, "a"); } catch (NullPointerException e) { System.out.println("hashTable put (null, a) NullPointerException"); } try { hashTable.put("a", null); } catch (Exception e) { System.out.println("hashTable put (a, null) NullPointerException"); } System.out.println("hashTable: " + hashTable); //3. TreeMap null test TreeMap<String, String> treeMap = new TreeMap<>(); try { treeMap.put(null, "a"); } catch (NullPointerException e) { System.out.println("treeMap put (null, a) NullPointException"); } treeMap.put("a", null); treeMap.put("b", null); System.out.println("treeMap: " + treeMap); } }
执行结果如下:
hashMap: {null=null, a=null, b=null} hashTable put (null, a) NullPointerException hashTable put (a, null) NullPointerException hashTable: {} treeMap put (null, a) NullPointException treeMap: {a=null, b=null}
二、是否是线程安全的
HashMap 和 TreeMap均不是线程安全的,如需要线程安全时,可使用Collections的synchronizedXxx()方法获取到对应的线程安全对象。
Hashtable 是线程安全的。
Java 集合总结
java 集合类主要由两个接口派生而出,Collection 和 Map接口。
一、Collection 族
其子接口有,Set,Queue和List接口。
1、Set 无序集合,集合中元素不可重复,常用Set类。
HashSet 元素的排列无序,不是线程同步的,集合中的元素可以为null,但是只可以有一个,其中的元素,因为不可以重复,所以需要判断两个对象是否相等,判断标准为两个对象通过equals()判断为true,且hashCode()方法返回值也相等。LinkedHashSet是其子类,它依然是一个HashSet,但内部使用链表记录了元素的添加顺序,所以其中元素的顺序与添加顺序是一致的。
TreeSet 内部使用红黑树来存储集合元素,加入TreeSet中的元素需要实现Comparable接口,因为TreeSet需要调用compareTo方法对元素进行比较从而排序,所以TreeSet中的元素顺序,不是插入顺序,而是compareTo的比较顺序。TreeSet判断两个对象是否相等的唯一标准就是compareTo返回值是否为0。若内部元素未实现Comparable接口,则需要在创建TreeSet对象时为其指名排序规则,以一个Comparator对象与集合关联,以指名排序规则。
EnumSet 专门为Enum对象设计的Set。
2、List 代表一个有序可重复的集合,且每一个元素都有对应的索引。
ArrayList 典型的List 实现类。
3、Queue 模拟队列的数据结构
PriorityQueue 标准的对列实现类,不过其队列中元素的排序并非按照入队顺序排列,而是依照元素实现的Comparable接口或者与集合绑定的Comparator对象定义的标准进行排列的,在出队时按照元素的排列顺序进行出队。
Deque 是Queue的子接口。
ArrayDeque是 Deque的典型实现类,实现双向队列,也可用作Stack来使用。
LinkedList 实现了List接口同时也实现了Deque接口,所以它是一个功能强大的结合,即可作为List使用,也可作为双向队列或栈来使用。
二、Map族
参照面试问题的回答,另外就是有几个重要的实现类:
WeakHashMap,保留对Key所引用对象的弱引用,可在key所引用的对象没有其它引用时,自动删除该key-value,以保证该元素的释放。
Properties,封装了对属性文件的读写,可以方便的将key-value的属性文件读入Properties对象中,也可方便的将Properties对象方便的存入属性文件中。