点击上方 Java后端,选择 设为星标
优质文章,及时送达
作者:平凡希
cnblogs.com/xiaoxi/p/6089984.html
一、集合框架图
简化图:
说明:对于以上的框架图有如下几点说明
1、所有集合类都位于java.util
包下。Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
2、集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。
3、抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。
4、实现类:8个实现类(实线表示),对接口的具体实现。
5、Collection 接口是一组允许重复的对象。
6、Set 接口继承 Collection,集合元素不重复。
7、List 接口继承 Collection,允许重复,维护元素插入顺序。
8、Map接口是键-值对象,与Collection接口没有什么关系。
9、Set、List和Map可以看做集合的三大类:
-
List集合是有序集合,集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
-
Set集合是无序集合,集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问(也是集合里元素不允许重复的原因)。
-
Map集合中保存Key-value对形式的元素,访问时只能根据每项元素的key来访问其value。
二、总体分析
-
List是一个有序的队列,每一个元素都有它的索引。第一个元素的索引值是0。List的实现类有LinkedList, ArrayList, Vector, Stack。
-
Set是一个不允许有重复元素的集合。Set的实现类有HastSet和TreeSet。HashSet依赖于HashMap,它实际上是通过HashMap实现的;TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。
有了上面的整体框架之后,我们接下来对每个类分别进行分析。
三、Collection接口
contains()
方法检测集合中是否包含指定的元素,toArray()方法返回一个表示集合的数组。
iterator()
函数,它的作用是返回一个Iterator接口。通常,我们通过Iterator迭代器来遍历集合。ListIterator是List接口所特有的,在List接口中,通过
ListIterator()
返回一个ListIterator对象。
1.List接口
ArrayList、LinkedList、Vector、Stack
。
(1)ArrayList
size、isEmpty、get、set、iterator
和 listIterator 操作都以固定时间运行。add 操作以分摊的固定时间运行,也就是说,添加 n 个元素需要 O(n) 时间(由于要考虑到扩容,所以这不只是添加元素会带来分摊固定时间开销那样简单)。
(2)LinkedList
get,remove,insert
方法在LinkedList的首部或尾部。
List list = Collections.synchronizedList(new LinkedList(...));
(3)Vector
(4)Stack
2.Set接口
e1.equals(e2)==true
,则必定会产生某些问题。Set接口有三个具体实现类,分别是散列集HashSet、链式散列集LinkedHashSet和树形集TreeSet。
此外需要说明一点,在set接口中的不重复是有特殊要求的。
public class Test{
public static void main(String[] args) {
Set<String> set=new HashSet<String>();
set.add("Hello");
set.add("world");
set.add("Hello");
System.out.println("集合的尺寸为:"+set.size());
System.out.println("集合中的元素为:"+set.toString());
}
}
集合的尺寸为:2
集合中的元素为:[world, Hello]
public class TestSet {
public static void main(String[] args){
Set<String> books = new HashSet<String>();
//添加一个字符串对象
books.add(new String("Struts2权威指南"));
//再次添加一个字符串对象,
//因为两个字符串对象通过equals方法比较相等,所以添加失败,返回false
boolean result = books.add(new String("Struts2权威指南"));
System.out.println(result);
//下面输出看到集合只有一个元素
System.out.println(books);
}
}
false
[Struts2权威指南]
(1)HashSet
Mutable Object
)。如果一个Set中的可变元素改变了自身状态导致
Object.equals(Object)=true
将导致一些问题。
(2)LinkedHashSet
(3)TreeSet
注意:TreeSet集合不是通过hashcode和equals函数来比较元素的.它是通过compare或者comparaeTo函数来判断元素是否相等.compare函数通过判断两个对象的id,相同的id判断为重复元素,不会被加入到集合中。
四、Map接口
1.HashMap
2.LinkedHashMap
注意,此实现不是同步的。如果多个线程同时访问链接的哈希映射,而其中至少一个线程从结构上修改了该映射,则它必须保持外部同步。由于LinkedHashMap需要维护元素的插入顺序,因此性能略低于HashMap的性能,但在迭代访问Map里的全部元素时将有很好的性能,因为它以链表来维护内部顺序。
compareTo()
方法返回0,则认为这两个key相等。
equals()
方法,TreeMap中判断相等的标准是:两个key通过
equals()
方法返回为true,并且通过
compareTo()
方法比较应该返回为0。
五、Iterator 与 ListIterator详解
1.Iterator
public interface Iterator<E> {}
-
boolean hasNext():判断集合里是否存在下一个元素。如果有,hasNext()方法返回 true。
-
Object next():返回集合里下一个元素。
-
void remove():删除集合里上一次next方法返回的元素。
public class IteratorExample {
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<String>();
a.add("aaa");
a.add("bbb");
a.add("ccc");
System.out.println("Before iterate : " + a);
Iterator<String> it = a.iterator();
while (it.hasNext()) {
String t = it.next();
if ("bbb".equals(t)) {
it.remove();
}
}
System.out.println("After iterate : " + a);
}
}
Before iterate : [aaa, bbb, ccc]
After iterate : [aaa, ccc]
注意:
-
Iterator只能单向移动。
-
Iterator.remove()是唯一安全的方式来在迭代过程中修改集合;如果在迭代过程中以任何其它的方式修改了基本集合将会产生未知的行为。而且每调用一次
next()
方法,
remove()
方法只能被调用一次,如果违反这个规则将抛出一个异常。
2.ListIterator
listIterator()
方法产生一个指向List开始处的ListIterator, 还可以调用
listIterator(n)
方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
public interface ListIterator<E> extends Iterator<E> {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove();
void set(E e);
void add(E e);
}
-
双向移动(向前/向后遍历).
-
产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引.
-
可以使用
set()
方法替换它访问过的最后一个元素.
-
可以使用
add()
方法在
next()
方法返回的元素之前或
previous()
方法返回的元素之后插入一个元素.
public class ListIteratorExample {
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<String>();
a.add("aaa");
a.add("bbb");
a.add("ccc");
System.out.println("Before iterate : " + a);
ListIterator<String> it = a.listIterator();
while (it.hasNext()) {
System.out.println(it.next() + ", " + it.previousIndex() + ", " + it.nextIndex());
}
while (it.hasPrevious()) {
System.out.print(it.previous() + " ");
}
System.out.println();
it = a.listIterator(1);
while (it.hasNext()) {
String t = it.next();
System.out.println(t);
if ("ccc".equals(t)) {
it.set("nnn");
} else {
it.add("kkk");
}
}
System.out.println("After iterate : " + a);
}
}
Before iterate : [aaa, bbb, ccc]
aaa, 0, 1
bbb, 1, 2
ccc, 2, 3
ccc bbb aaa
bbb
ccc
After iterate : [aaa, bbb, kkk, nnn]
六、异同点
1.ArrayList和LinkedList
-
ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
-
对于随机访问get和set,ArrayList绝对优于LinkedList,因为LinkedList要移动指针。
-
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
2.HashTable与HashMap
-
都实现了
Map、Cloneable、java.io.Serializable
接口。
-
都是存储"键值对(key-value)"的散列表,而且都是采用拉链法实现的。
-
Dictionary是一个抽象类,它直接继承于Object类,没有实现任何接口。Dictionary类是JDK 1.0的引入的。虽然Dictionary也支持“添加key-value键值对”、“获取value”、“获取大小”等基本操作,但它的API函数比Map少;而且Dictionary一般是通过Enumeration(枚举类)去遍历,Map则是通过Iterator(迭代M器)去遍历。 然而由于Hashtable也实现了Map接口,所以,它即支持Enumeration遍历,也支持Iterator遍历。
-
AbstractMap是一个抽象类,它实现了Map接口的绝大部分API函数;为Map的具体实现类提供了极大的便利。它是JDK 1.2新增的类。
3.HashMap、Hashtable、LinkedHashMap和TreeMap比较
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.TreeMap;
public class MapTest {
public static void main(String[] args) {
//HashMap
HashMap<String,String> hashMap = new HashMap();
hashMap.put("4", "d");
hashMap.put("3", "c");
hashMap.put("2", "b");
hashMap.put("1", "a");
Iterator<String> iteratorHashMap = hashMap.keySet().iterator();
System.out.println("HashMap-->");
while (iteratorHashMap.hasNext()){
Object key1 = iteratorHashMap.next();
System.out.println(key1 + "--" + hashMap.get(key1));
}
//LinkedHashMap
LinkedHashMap<String,String> linkedHashMap = new LinkedHashMap();
linkedHashMap.put("4", "d");
linkedHashMap.put("3", "c");
linkedHashMap.put("2", "b");
linkedHashMap.put("1", "a");
Iterator<String> iteratorLinkedHashMap = linkedHashMap.keySet().iterator();
System.out.println("LinkedHashMap-->");
while (iteratorLinkedHashMap.hasNext()){
Object key2 = iteratorLinkedHashMap.next();
System.out.println(key2 + "--" + linkedHashMap.get(key2));
}
//TreeMap
TreeMap<String,String> treeMap = new TreeMap();
treeMap.put("4", "d");
treeMap.put("3", "c");
treeMap.put("2", "b");
treeMap.put("1", "a");
Iterator<String> iteratorTreeMap = treeMap.keySet().iterator();
System.out.println("TreeMap-->");
while (iteratorTreeMap.hasNext()){
Object key3 = iteratorTreeMap.next();
System.out.println(key3 + "--" + treeMap.get(key3));
}
}
}
HashMap-->
3--c
2--b
1--a
4--d
LinkedHashMap-->
4--d
3--c
2--b
1--a
TreeMap-->
1--a
2--b
3--c
4--d
4.HashSet、LinkedHashSet、TreeSet比较
Set接口
HashSet
-
不能保证元素的排列顺序,顺序有可能发生变化。
-
不是同步的。
-
集合元素可以是null,但只能放入一个null。
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
LinkedHashSet
TreeSet类
CompareTo(Object obj)
方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个
compareTo(Object obj)
方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)
方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是负数,则表明obj1小于obj2。如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0。
int compare(T o1,T o2)
方法。
package com.test;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.TreeSet;
/**
* @description 几个set的比较
* HashSet:哈希表是通过使用称为散列法的机制来存储信息的,元素并没有以某种特定顺序来存放;
* LinkedHashSet:以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代;
* TreeSet:提供一个使用树结构存储Set接口的实现,对象以升序顺序存储,访问和遍历的时间很快。
* @author Zhou-Jingxian
*
*/
public class SetDemo {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<String>();
hs.add("B");
hs.add("A");
hs.add("D");
hs.add("E");
hs.add("C");
hs.add("F");
System.out.println("HashSet 顺序:\n"+hs);
LinkedHashSet<String> lhs = new LinkedHashSet<String>();
lhs.add("B");
lhs.add("A");
lhs.add("D");
lhs.add("E");
lhs.add("C");
lhs.add("F");
System.out.println("LinkedHashSet 顺序:\n"+lhs);
TreeSet<String> ts = new TreeSet<String>();
ts.add("B");
ts.add("A");
ts.add("D");
ts.add("E");
ts.add("C");
ts.add("F");
System.out.println("TreeSet 顺序:\n"+ts);
}
}
HashSet 顺序:[D, E, F, A, B, C]
LinkedHashSet 顺序:[B, A, D, E, C, F]
TreeSet 顺序:[A, B, C, D, E, F]
5、Iterator和ListIterator区别
iterator()
来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:
-
ListIterator有
add()
方法,可以向List中添加对象,而Iterator不能
-
ListIterator和Iterator都有
hasNext()
和
next()
方法,可以实现顺序向后遍历,但是ListIterator有
hasPrevious()
和
previous()
方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
-
ListIterator可以定位当前的索引位置,
nextIndex()
和
previousIndex()
可以实现。Iterator没有此功能。
-
都可实现删除对象,但是ListIterator可以实现对象的修改,
set()
方法可以实现。Iierator仅能遍历,不能修改。
6、Collection 和 Collections区别
java.util.Collection
是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class TestCollections {
public static void main(String args[]) {
//注意List是实现Collection接口的
List list = new ArrayList();
double array[] = { 112, 111, 23, 456, 231 };
for (int i = 0; i < array.length; i++) {
list.add(new Double(array[i]));
}
Collections.sort(list);
for (int i = 0; i < array.length; i++) {
System.out.println(list.get(i));
}
// 结果:23.0 111.0 112.0 231.0 456.0
}
}
。同时标星(置顶)本公众号可以第一时间接受到博文推送。
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
相关文章
暂无评论...