Java基础知识回顾第五篇 - 各种容器类的选择

阅读更多

    在Java实际开发中,我们会常常用到容器,那么各种容器类我们该如何进行抉择呢?在这里进行一个简单的总结。

 

1、对List的选择

    对于随机访问的get()和set()操作,背后有数组支撑的List仅仅ArrayList稍微快一点,但是对于LinkedList,相同的操作会产生高昂的性能消耗,因为它本身就不是针对随机访问操作而设计的。

    避免使用Vector,它只是存在于支持遗留代码的类库中。最佳的做法就是将ArrayList作为默认首选,只有当你需要使用额外的功能的时候,或者当程序的性能因为经常进行插入和删除操作而变差的时候,就去选择LinkedList。如果元素的数量确定,那么我们既可以选择List,也可以选择真正的数组。

    如果是在多线程环境下呢?我们选择CopyOnWriteArrayList!

 

补充:List有序。

package com.tu.test;

 

import java.util.ArrayList;

import java.util.LinkedList;

import java.util.List;

 

public class ListTest {

public static void main(String[] args){

System.out.println("ArrayList:");

List myList = new ArrayList();

myList.add("WuHoujian");

myList.add(null);

myList.add(null);

System.out.println(myList.toString());

System.out.println("index of null is :" + myList.indexOf(null));

 

System.out.println("LinkedList:");

LinkedList myLinkedList = new LinkedList();

myLinkedList.addFirst("test11");

myLinkedList.addFirst("test22");

myLinkedList.addFirst(null);

myLinkedList.addFirst(null);

System.out.println(myLinkedList.toString());

System.out.println("index of null is :" + myLinkedList.indexOf(null));

}

}

 

输出:

ArrayList:

[WuHoujian, null, null]

index of null is :1

LinkedList:

[null, null, test22, test11]

index of null is :0

 

2、对Set的选择

    HashSet的性能基本上总是比TreeSet好,特别是在添加和查询元素的时候。那什么时候我们应该选择TreeSet呢?当我们需要一个排好序的Set时,就选择TreeSet,因为其内部结构支持排序。

    LinkedHashSet和HashSet呢?由于LinkedHashSet是由链表实现的,插入删除元素操作需要更高的代价,所以我们也需要结合具体的场景进行选择(类似LinkedList和ArrayList)。

 

补充:Set的底层实现是基于Map实现的,HashSet底层是HashMap,TreeSet底层是TreeMap。从下面代码我们可以看出,HashSet是无序的,TreeSet会进行排序。

package com.tu.test;

 

import java.util.HashSet;

import java.util.Set;

import java.util.TreeSet;

 

public class SetTest {

public static void main(String [] args){

System.out.println("HashSet:");

Set set1 = new HashSet();

set1.add("test111");

set1.add("test222");

set1.add("test333");

System.out.println(set1.toString());

System.out.println(set1.iterator().next());

 

System.out.println("TreeSet:");

TreeSet set2 = new TreeSet();

set2.add("a4");

set2.add("a2");

set2.add("a5");

System.out.println(set2.toString());

}

}

 

输出:

HashSet:

[test222, test111, test333]

test222

TreeSet:

[a2, a4, a5]

 

3、对Map的选择

    排除IdentityHashMap,所有的Map实现的插入操作都会随着Map尺寸的变大而明显变慢。

    Hashtable的性能和HashMap大体上相当,因为HashMap是用来代替Hashtable的。那么它们两者之间有什么区别呢?主要有三点:第一点就是Hashtable是基于旧的Dictionary实现的,而HashMap是Map接口的实现;第二点就是Hashtable是同步的,在多线程环境中使用,而HashMap不是同步的;第三点不同就是HashMap可以允许一个key为null,任意个value为null。

    TreeMap通常比HashMap要慢。同TreeSet一样,TreeMap是一种创建有序列表的表达方式。

    LinkedHashMap在插入时比HashMap慢一点,因为它除了维护散列数据结构之外,还需要维护链表结构。

 

补充:从下面的Demo以及输出结果可以看出,在Map中null元素永远被放在第一个元素;另外当键值相同时,表面上看到的是覆盖,底层实际上依旧保持着原有的数据。看了源代码会知道,Map底层是基于数组实现,数组类型是Entry类型,包括key,value,next和hash几个属性,当有重复的键值(准确地说是key的hash值),原有的值value会被放到Entry的next属性中,这样也解决了Map的冲突问题。

package com.tu.test;

 

import java.util.HashMap;

import java.util.Map;

import java.util.Map.Entry;

 

public class MapTest {

 

public static void main(String[] args) {

Map map1 = new HashMap();

map1.put("name", "WuHoujian");

map1.put(null, "I'm null");

Object str = map1.put("name", "William");

System.out.println("有两个相同的key,前一次的值为:" + str);

int i = 1;

for (Entry entry : map1.entrySet()) {

System.out.println("map中第" + i +"元素:" + entry.getKey() + "=" + entry.getValue());

i++;

}

}

 

}

输出:

有两个相同的key,前一次的值为:WuHoujian

map中第1元素:null=I'm null

map中第2元素:name=William

 

 

注:以上提到的各种容器类,大家如果感兴趣,可以多看看底层源代码的实现,深入了解一下各自的实现,对它们有一个更深刻的认识。

阅读源码之后的心得,大家后面可以分享一下大笑

 

你可能感兴趣的:(List,Set,Map,Java容器类)