Java集合总结
来源:互联网 发布:没有网络怎么重装系统 编辑:程序博客网 时间:2024/06/01 10:11
PS:
List和Set都有iterator()来取得其迭代器。对List来说,你还可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的,Iterator和ListIterator主要区别在以下方面:
1. ListIterator有add()方法,可以向List中添加对象,而Iterator不能。Iterator是ListIterator的父接口。
2. ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。
3. ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
4. 都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。
因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。
org.apache.commons.collections.iterators.ArrayIterator就可以实现此功能。一般情况下,我们使用Iterator就可以了,如果你需要进行记录的前后反复检索的话,你就可以使用ListIterator来扩展你的功能,(有点象JDBC中的滚动结果集)
5 ListIterator中具备着对被遍历的元素进行增删改查的方法,可以对元素进行逆向遍历。
一 前言:讲集合collection之前,我们先分清三个概念:
colection 集合,用来表示一种数据结构(集合--逻辑结构的一种)
Collection 集合接口,指的是 java.util.Collection接口,是 Set、List 和 Queue 接口的超类接口
Collections 集合工具类,指的是 java.util.Collections 类。
Collection完整图---VS---重点学习图
重点学习图:(如下)
二 分别介绍
- List 关注事物的索引列表
- Set 关注事物的唯一性
- Queue 关注事物被处理时的顺序
- Map 关注事物的映射和键值的唯一性
(一) List
List接口:有序的列表,允许重复元素,它的有序是指假如元素时的顺序。
1) ArrayList: 数组列表。内部采用数组结构来存储元素, 根据索引来存取元素的效率很高
适合于:要遍历显示所有元素的情况。不适合需要频繁增删元素的情况。
2) LinkedList:链式列表。内部采用双向链表结构来存储元素.适合于:需要频繁增删元素的情况下。但不要使用根据索引来获取元素。
双向链表结构不仅可以后向迭代,还可以前向迭代,并且支持元素的修改。
ArrayList 可以将它理解成一个可增长的数组,它提供快速迭代和快速随机访问的能力。 LinkedList 中的元素之间是双链接的,当需要快速插入和删除时LinkedList成为List中的不二选择。
Vector 是ArrayList的线程安全版本,性能比ArrayList要低,现在已经很少使用.
Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。
(二)Set
2) 常用的数据类型:8种基本数据类型包装类、String类、Date类、Calendar类它们
a) 散列表的存储原理:
a) 可排序的类必须实现java.lang.Comparable接口,在compareTo方法中定义比较规则。
int compareTo(T t);如果当前对象小于指定对象,返回负整数;大于,返回正整数。等于,返回0。
b) 为了便于使用各种排序规则的要求,可以通过实现Comparator<T>接口来定义比较器类。
int compare(T t1, T t2);如果t1对象小于t2对象,返回负整数;大于,返回正整数。等于,返回0。
TreeSet 当不希望集合中有重复值,并且希望按照元素的自然顺序进行排序时可以采用此类。(TreeSet采用红黑树的数据结构进行排序元素,使用它可以从 Set中提取有序(升序或者降序)的序列。需要注意的是,存入自定义类时,TreeSet需要维护元素的存储顺序,因此自定义类要实现Comparable接口并定义compareTo方法。若不实现Comparable接口/Comparator接口,则按自然顺序意思是某种和插入顺序无关,而是和元素本身的内容和特质有关的排序 方式,譬如“abc”排在“abd”前面。)
Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在 HashSet中存储位置。 简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等 。注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法 比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
(三)Queue(用于保存将要执行的任务列表。)
LinkedList 同样实现了Queue接口,可以实现先进先出的队列。
(四) Map ( Map关心的是唯一的标识符。他将唯一的键映射到某个元素。当然键和值都是对象。)
a) 作为映射对的键对应的类要重写equals和hashCode方法,以实现键相等规则。
b) 因为键是用散列表存放的,所以键/值对在Map中的存放是无序的。
c) 适合于:需要以键/值对形式存放元素时。它的存取效率很高。它是使用频率最高的一个集合类。
b) 另一种方式,把一个针对键的比较器(实现Comparator接口的类)对象传入该类的构造器来创建。
LinkedHashMap 当需要键值对,并且关心插入顺序时可采用它。LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。LinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺序。(因为是双向链表,其除了能向后遍历,还支持向前遍历,并可在遍历过程中删除元素)
TreeMap 当需要键值对,并关心元素的自然排序时可采用它。TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。不仅可以保持顺序,而且可以用于排序.
TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。
LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。
三 列表、集合与数组的互相转换
1 List、Set转为数组
Set转换成数组可以使用Set的toArray方法,返回一个Object数组。
如果List或者Set中元素的 类型 都为 A,那么可以使用带参数的toArray方法,将得到类型为A的数组,具体语句是(A[])set.toArray(new A[0]),例: ArrayList<Integer> lt=new ArrayList<Integer>();
2 数组只能直接转化为List
数组转换成List可以使用Arrays的asList静态方法,得到一个List。
数组转换成Set时,需要先将数组转换成List,再将List构造Set。 List lt=new HashSet( List) ; 使用Set的构造函数,函数参数为Collection类型。
四 线程安全的集合类
线程安全:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程如何交替执行,并且在主调代码中不需要额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的。
Vector-----ArrayLIst
HashTable---HashMap
Vector和Hashtable在各自的方法上都加了synchronized关键字来保持同步。
b:
c:
1
public
boolean
add(E e) {
2
ensureCapacity(size +
1
);
// Increments modCount!!
3
elementData[size++] = e;
4
return
true
;
5
}
在多线程的操作下导致扩容和赋值操作的不统一导致了出错。
f:
HashMap多线程下添加元素出错的原因分析:
01
public
V put(K key, V value) {
02
...
03
addEntry(hash, key, value, i);
04
...
05
}
06
07
void
addEntry(
int
hash, K key, V value,
int
bucketIndex) {
08
Entry<K,V> e = table[bucketIndex];
09
table[bucketIndex] =
new
Entry<K,V>(hash, key, value, e);
10
if
(size++ >= threshold)
11
resize(
2
* table.length);
12
}
13
14
void
resize(
int
newCapacity) {
15
Entry[] oldTable = table;
16
int
oldCapacity = oldTable.length;
17
if
(oldCapacity == MAXIMUM_CAPACITY) {
18
threshold = Integer.MAX_VALUE;
19
return
;
20
}
21
22
Entry[] newTable =
new
Entry[newCapacity];
23
transfer(newTable);
24
table = newTable;
25
threshold = (
int
)(newCapacity * loadFactor);
26
}
从代码中,可以看到,如果发现哈希表的大小超过阀值threshold,就会调用resize方法,扩大容量为原来的两倍,而扩大容量的做法是新建一个Entry[]。
如果在默认情况下,一个HashMap的容量为16,加载因子为0.75,那么阀值就是12,所以在往HashMap中put的值到达12时,它将自动扩容两倍。如果两个线程同时遇到HashMap的大小达到12的倍数时,就很有可能会出现在将oldTable转移到newTable的过程中遇到问题,从而导致最终的HashMap的值存储异常。
五 重点提示:
1 遗留集合:JDK1.0或1.1中就有的集合类。
1) Vector: 向量。可以认为Vector就是旧版的ArrayList。Vector是同步的,即线程安全。首选ArrayList
2) Stack:栈。具有LIFO的功能。JDK1.6中建议使用Deque,Vetcor的子类。
3) Hashtable:可以认为是旧版的HashMap。Hashtable是同步的,即线程安全。
4) Properties:属性集。它是Hashtable的子类。线程安全的。
a) Properties可保存在流中或从流中加载。
b) 属性列表中每个键及其对应值都是一个字符串。不是泛型类。
c) 不建议使用put和get方法存放键值对。应该改用setProperty(String key, String value);和String getProperty(String key);
2 . 集合工具类Collections:它针对集合提供了一些常用算法。
1) public static void sort(List<T> list); 元素的自然顺序对指定列表按升序排序。
2) public static void shuffle(List<?> list);混排。洗牌算法。
public static <T> Collection<T> synchronizedCollection(Collection<T> c):返回指定 collection 支持的同步(线程安全的)collection。
3 一些补充--关键点
1 HashSet是通过HashMap实现的,TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key。
2. Map的key和Set都有一个共同的特性就是集合的唯一性.TreeMap更是多了一个排序的功能.
3. hashCode和equal()是HashMap用的, 因为无需排序所以只需要关注定位和唯一性即可
a. hashCode是用来计算hash值的,hash值是用来确定hash表索引的.
b. hash表中的一个索引处存放的是一张链表, 所以还要通过equal方法循环比较链上的每一个对象才可以真正定位到键值对应的Entry.
c. put时,如果hash表中没定位到,就在链表前加一个Entry,如果定位到了,则更换Entry中的value,并返回旧value
4. 由于TreeMap需要排序,所以需要一个Comparator为键值进行大小比较.当然也是用Comparator定位的.
a. Comparator可以在创建TreeMap时指定
b. 如果创建时没有确定,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口.
c. TreeMap是使用Tree数据结构实现的,所以使用compare接口就可以完成定位了.
5、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
6、Set和Collection拥有一模一样的接口。
7、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)...。(add/get)
8、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
9、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
HashMap会利用对象的hashCode来快速找到key。
* hashing
哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个值存储在一个array中。
我们都知道所有存储结构中,array查找速度是最快的。所以,可以加速查找。
发生碰撞时,让array指向多个values。即,数组每个位置上又生成一个梿表。
10、Map中元素,可以将key序列、value序列单独抽取出来。
使用keySet()抽取key序列,将map中的所有keys生成一个Set。
使用values()抽取value序列,将map中的所有values生成一个Collection。
为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。
1) 存放的数据
需要有序-List
无序-Set
“key-value”对-Map
2) 读的效率和改的效率
Array* - 读快改慢
Linked* - 改快读慢
Hash* - 介于两者之间
- java集合------List集合总结
- java集合------Map集合总结
- Java集合--Set集合总结
- java集合类总结
- Java集合框架总结
- java集合的总结!
- java集合类总结
- JAVA集合类总结
- Java集合总结
- java集合类总结
- java集合类总结
- java集合类总结
- JAVA集合类总结
- Java集合总结
- java集合框架总结
- Java集合框架总结
- Java集合容器总结
- java集合类总结
- 使用gSoap开发Web Service C/C++客户端
- 二分查找——UVa 10706 - Number Sequence
- AIX上提供了XLC编译器也提供了CC编译器,这两个编译器有什么差别呢?
- python等笔记
- 算法导论-第14章
- Java集合总结
- The VC programming specifications - programmers should write code like this
- 添加或删除项并动态记录项的值
- 【鸡肋实验】数据线性相关性对机器学习的影响(一)
- android 框架试用--spring for android
- 《c陷阱与缺陷》笔记--extern
- 事务隔离级别
- 嵌入式ucos系统上移植实现USB UVC协议(支持HD 720P Webcam)
- Ext.TabPanel的api简介