欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-08 08:41:29
...

    在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<Object> myList = new ArrayList<Object>();

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<Object> myLinkedList = new LinkedList<Object>();

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<Object> set1 = new HashSet<Object>();

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<Object> set2 = new TreeSet<Object>();

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<String,Object> map1 = new HashMap<String,Object>();

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<String, Object> 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

 

 

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

阅读源码之后的心得,大家后面可以分享一下Java基础知识回顾第五篇 - 各种容器类的选择
            
    
    博客分类: Java基础知识回顾 ListSetMapJava容器类