您的位置:首页 > 编程语言 > Java开发

[疯狂Java讲义精粹] 第六章|Java集合

2012-12-26 19:15 429 查看
0. Java集合分Set、List、Map和Queue. Set是无序, 不可重复的集合; List有序, 可重复; Map具有映射关系; Queue代表队列集合.

1. 集合类主要用于保存、盛装其他数据, 因此集合类也叫容器类. (集合类在java.util包下. (java.util.concurrent包下有一些多线程支持的集合类)).

数组元素可以使基本类型的值, 也可以是对象; 集合只能保存对象. (所言对象, 都指对象的引用变量.)
集合类主要由两个接口派生而出: Collection 和 Map. (Map保存key-value对, key不能重复.)

2. Collection是List、Set和Queue接口的父接口. 常用方法:

boolean add(Object o)
boolean add(Collection c): 把集合c里的所有元素添加到指定集合里. 如果集合对象被添加对象改变了, 则返回true.
void clear(): 清除所有元素, 将长度变为0.
boolean contains(Object o)
boolean containsAll(Collection c): 返回集合里是否包含集合c里所有元素.
boolean isEmpty(): 是否为空. 长度0则返回true.
Iterator iterator(): 返回一个Iterator对象, 用于遍历集合里的元素.
boolean remove(Object o): 删除集合中指定元素o. 包含多个元素o时, 全删, 返回true.
boolean removeAll(Collection c): 删除集合c中所有元素. 成功删除一个或以上时, 返回true.
boolean retainAll(Collection c): 从集合中删除c中不含的元素. 如果改变了调用该方法的集合, 返回true.
int size(): 返回元素个数.
Object[] toArray(): 把集合转换成一个数组.

3. System.out.println( c ); 输出集合对象时, 以[ele1, ele2, ele3, ...]形式输出.

4. Iterator接口也是集合框架的成员, 与Collection和Map接口不同的是Iterator主要用于遍历(迭代访问)Collection集合中的元素, Iterator对象也称跌倒器.

常用方法:

- bollean hasNext(): 如果遍历还没完成, 返回true.

- Object next(): 返回下个元素.

- void remove(): 删除集合里上一次next方法返回的元素.
使用Iterator对集合元素迭代时, 没有把元素本身传给迭代变量, 而是把集合元素的值传给迭代变量, 所以修改迭代变量的值对集合元素本身谬影响.
使用Iterator迭代过程中, 不能修改集合元素(可以用Iterator的remove方法), 否则引发异常(不一定报错. "一旦迭代过程中检测到该集合已经被修改(通常是程序中的其他线程修改), 立即引发java.util.ConcurrentModificationException错误.").

5. foreach循环: 用来迭代访问Collection集合的元素.
import java.util.*;

public class IteratorErrorTest
{
public static void main(String[] args) {
Collection books = new HashSet();
books.add("aaaaa");
books.add("bbbbb");
books.add("ccccc");
Iterator it = books.iterator();
while(it.hasNext())
{
String book = (String) it.next();
System.out.println(book);
if(book.equals("bbbbb"))
{
books.remove(book);    // *1
}
}
}
}
与Iterator接口迭代访问类似(指上面的4.2和4.3).

6. Set集合.

Set集合与Collection基本一样(行为略有不同, Set不允许包含重复元素), 没有提供任何额外的方法.
Set判断两对象是否相同用equals, 同时还需要他们的hashCode()方法返回值相等.

7. HashSet类时Set接口的实现, 按Hash算法来存储集合中的元素, 因此存取和查找性能良好.

集合元素可以使null.

HashSet不是同步的(两个或更多线程同时修改了HashSet集合时, 必须通过代码来保证其同步.).
存入元素时, 会调用hashCode()方法计算hashCode值, 决定该对象在HashSet中的存储位置.
需要重写对象的equals()方法时, 也要重写hashCode()方法(规则是, equals()返回true时, hashCode值也应相等.).
HashSet中每个能存储元素的"槽位(slot)"通常称为"桶(blucket)", 如果多个元素hashCode值相同, 但equals()返回false, 就需要在一个"桶"放多个元素, 导致性能下降.
重写hashCode()方法的基本规则:

- 运行过程中, 同一个对象多次调用hashCode()方法应返回相同值.

- 两对象用equals()方法比较返回true时, 他俩的hashCode值应相等.

- 对象中用作equals()方法比较标准的Field, 都应用来计算hashCode值.

8. LinkedHashSet类, 是HashSet类的子类. 它也是用hashCode值来决定元素的存储位置, 但同时使用链表维护元素的次序, 使得元素看起来像是以插入顺序保存的(遍历时将按元素添加顺序来访问集合里的元素). 由于要维护链表, 性能略低于HashSet, 却也因为维护链表, 迭代时性能很好.

9. TreeSet类, 是SortedSet接口的实现类, 可以确保元素处于排序状态.

与HashSet相比, TreeSet提供了几个额外方法:

- Comparator comparator(): 如果TreeSet采用了定制排序, 返回定制排序所使用的Comparator; 否则返回null.

- Object first(): 返回集合中的第一个元素.

- Object last()

- Object lower(Object e): 返回位于指定元素前的一个元素( 即小雨指定元素的最大元素, 参考元素不需要时TreeSet集合里的元素).

- Object higher(Object e)

- SortedSet subSet(fromElement, toElement): 返回此Set的子集, 从fromElement(包含) 到 toElement(不包含).

- SortedSet headSet(toElement): 返回子集, 由小于toElement的元素组成.

- SortedSet tailSet(fromElement): 子集, 有大于或等于fromElement的元素组成.
TreeSet采用红黑树的数据结构存储集合元素. 排序方法有 自然排序和定制排序.
自然排序: 调用集合元素的compareTo(Object obj)方法比较大小, 升序排列.

- obj1.compareTo(obj2); 返回0表相等, 正整数表obj1>obj2, 负整数表示...

- 试图把一个对象添加到TreeSet时, 该对象必须实现Comparable接口, 否则抛出异常.

-----------------------------------实现了Comparable接口的常用类-----------------------

1. BigDecimal、BigInteger以及所有的数值型对应的包装类: 按数值大小比.

2. Character: 按对应UNICODE值比.

3. Boolean: true > false.

4. String: 按字符串中的UNICODE值比(一个个的比).

5. Date、Time: 后面的时间比前面的大.

-------------------------------------------------------------------------------------------------------

- 添加时, 该元素必须与集合中其他元素时同一类的实例(因为compareTo()方法只能比较同类).

- TreeSet判断两对象相等的唯一标准: compareTo(Object obj)方法是否返回0. 返0则相等.
定制排序: 通过Comparator接口里的compara(T o1, T o2)方法比较o1和o2的大小:o1>o2返回正整数, 小于返负整数, 等返0.
import java.util.*;

class M
{
int age;
public M(int age)
{
this.age = age;
}
public String toStrig()
{
return "M[age:" + age + "]";
}
}
public class TreeSetTest4
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new Comparator()
{
public int compare(Object o1, Object o2)
{
M m1 = (M) o1;
M m2 = (M) o2;
return m1.age > m2.age ? -1
: m1.age < m2.age ? 1 : 0;
}
});
ts.add(new M(5));
ts.add(new M(-3));
ts.add(new M(9));
System.out.println(ts);
}
}


10. EnumSet类是为枚举类设计的集合类, 其元素都必须是指定枚举类型的枚举值. EnumSet集合是有序的(EnumSet以枚举值在Enum类内的定义顺序来决定集合元素顺序).

EnumSet集合不允许加入null元素.
EnumSet类没有暴露任何构造器来创建实例, 应该用它的static方法来创建EnumSet对象. 常用的有:

- static EnumSet allOf(Class elementType): 创建一个包含指定枚举类里所有枚举值的EnumSet对象.

- static EnumSet complementOf(EnumSet s): 创建一个元素类型与s里元素相同的EnumSet集合, 其元素是s所不含的、这个枚举类型里的其他元素(新集合的元素 + s里的元素 = 该枚举类的所有元素).

- static EnumSet copyOf(Collection c): 使用普通集合创建EnumSet集合.

- static EnumSet copyOf(EnumSet s): 复制一个.

- static EnumSet noneOf(Class elementType): 创建一个元素类型为指定枚举类型的空EnumSet.

- static EnumSet of(E first, E... rest): 创建一个包含一个或多个枚举值的EnumSet集合, 传入的多个枚举值必须属于同一个枚举类.

- static EnumSet range(E from, E to): 创建一个包含从from(包含)枚举值到to(包含)枚举值范围内的所有枚举值的EnumSet集合.

11. Hash比TreeSet性能好(TreeSet要用红黑树维护集合元素次序), 需要一个保持排序的Set时才需要TreeSet.

12. List 元素有序, 可重复, 每个元素又对应的顺序索引(默认按添加顺序设置索引, 从0开始).

常用方法:

- void add(int index, Object element): 把element插入到index处.

- boolean addAll(int index, Collection c): 把c的所有元素插入到index处.

- List subList(int fromIndex, int toIndex): 返回从索引的fromIndex(包括)到toIndex(不包括)的元素组成的子集合.

-

-

- 不拉不拉不拉不拉...

List用equals比较两对象是否相等.
List额外提供了一个listIterator()方法, 返回一个ListIterator对象(ListIterator接口继承了Iterator接口, 提供了专门操作List的方法.). 比Iterator增加了:

- boolean hasPrevious(): 返回该迭代器关联的集合是否有还有上一个元素.

- Object previous()

- void add(): 在指定位置插入一个元素.

13. ArrayList和Vector类都是基于数组实现的List类, 它们封装了一个动态的、允许在分配的Object[]数组. ArrayList和Vector对象使用initialCapacity参数来设置该数组的长度, 当添加的元素超出了该数组的长度时, initialCapacity自动增加. 如果创建空的ArrayList和Vector集合时不指定initialCapacity参数, 则Object[]数组长度默认为10. 还有两个方法重新分配Object[] 数组. - void ensureCapacity(int
minCapacity): 将集合的Object[]数组长度增加minCapacity. - void trimToSize(): 调整ArrayList和Vector集合的Object[]数组长度为当前元素个数. (Vector很古老, JDK1.0时就有. 通常尽量少用Vector实现类. Vector是线程不安全的, ArrayList是线程安全的.)

14. Vector提供了一个Stack子类, 模拟"栈"结构. 常用方法: (Stack继承Vector, 所以也很老, 线程安全, 性能差, 因此较少使用. 用"栈"这种数据结构可考虑LinkedList.)

Object peek(): 返回"栈"的第一个元素, 但并不将该元素"pop"出栈.
Object pop(): 返回第一个元素, 并"pop".
void push(Object item): 讲一个元素"push"进栈.

15. 一个用于操作数组的工具类Arrays里有个内部类也叫ArrayList, Arrays.ArrayList是一个固定长度的List集合, 只能遍历, 不能增删.

16. Queue用于模拟"队列"这种数据结构, 先进先出(FIFO). 新元素插入(offer)到队列的尾部, 访问元素(poll)操作返回队列头部的元素. 通常不允许随机访问队列中的元素.

Queue接口常用的方法:

- void add(Object e): 将指定元素加入此队列尾部.

- Object element(): 获取队头元素, 不删除.

- boolean offer(Object e): 将指定元素加入队尾. (当使用有容量限制的队列时, 此方法通常比add(Object e)好.)

- Object peek(): 获取队头元素, 不删除. 如果队列为空, 返回null.

- Object poll(): 获取队头元素, 并删除. 为空, 返null.

- Object remove(): 获取队头元素, 并删除.
Queue接口有个PriorityQueue实现类. Queue还有个Deque接口, 代表"双端队列", 双端队列可以同时从两端增删元素, 因此它的实现类即可当成队列也可当成栈(Java为Deque提供ArrayDeque和LinkedList两个实现类).

17. PriorityQueue是个不标准的队列实现. 因为PriorityQueue保存队列元素的顺序是按队列元素大小重新排列的, 不符合FIFO.

PriorityQueue不允许插入null元素.
排序方式有自然排序和定制排序. (和TreeSet差不多.)

18. Deque是Queue的子接口. 常用方法:

void addFirst(Object e): 把e插入队列开头.

- void addLast(Object e)
Iterator descendingIterator(): 返回该双端队列对应的迭代器, 以逆向顺序迭代队列中的元素.
Object getFirst(): 获取第一个元素, 不删除.

- Object removeFirst(): 获取并删除第一个元素.

- Object getLast()

- Object removeLast()
Object removeFirstOccurrence(Object o): 删除该双端队列第一次出现的元素o.

- Object removeLastOccurrence(Object o)
boolean offerFirst(Object e): 把e插入队列开头.

- boolean offerFirst(Object e)
Object peekFirst(): 获取第一个元素, 不删. 若Deque为空, 返回null.

- Object peekLast()
Object pollFirst(): 获取第一个元素, 删. 空, 返null.

- Object pollLast()
Object pop(): pop出该双端队列所表示的栈的栈顶元素, 相等于removeFirst().

void push(Object e): 把e这个元素push进该双端队列所表示的栈的栈定, 相当于addFirst(e).
Object removeFirst(): 获取并删除

19. ArrayDeque是Deque接口的实现类. (创建时可以指定numElements参数, 用于指定Object[]数组的长度; 不指定的话, 长16.)

20. LinkedList是List和Deque接口的实现类.

21. Map 保存映射关系的数据. key不能重复.

* Java源码是先实现了Map, 然后通过包装一个所有value窦唯null的Map实现的Set集合. (所以就是他们很像.)
常用方法:

- void clear()

- Set entry Set(): 返回Map中包含的key-value对所组成的Set集合, 每个集合元素都是Map.Entry(Entry是Map的内部类)对象.

- Set keySet(): 返回Map中所有key组成的Set集合.

- Object put(Object key, Object value): 添加(or更新)一个键值对.

- void putAll(Map m)

- int size(): 键值对个数.

- Collection values(): Map里所有value组成的Collection.
HashMap和Hashtable是Map接口的实现类, 存取对象时, 判定两个key相等必须equals()返回true, 且hashCode值相等. 判定value只需equals()返true.
LinkedHashMap是HashMap的子类, 使用双向链表来维护key-value对的次序, 该链表负责维护Map的迭代顺序(与键值对插入顺序一致),
Properties是Hashtable的子类, 用于处理属性文件(Windows上的ini文件就是一属性文件). ----> 属性名: 属性值.
与Set接口类似, Map有SortedMap子接口, SortedMap有个TreeMap实现类.

22. hash: hash表里可以储存元素的位置叫"桶(bucket)", 通常一桶存一个元素 ,此时性能最佳: hash算法可以根据hashCode值算出桶的存储位置, 然后从同种取出元素. 但hash表的状态为open: 在发生"hash冲突"时, 单个桶会存储多个元素, 这些元素以链表形式存储, 必须按顺序搜索. HashSet和HashMap的hash表有一下属性:

容量(capacity): 桶数.
尺寸(size): 表中当前记录的数量.
负载因子(load factor): 等于size/capacity. (负载因子为0表示空的hash表, 0.5表示半满的散列表, 以此类推.) 轻负载的散列表冲突少、适宜插入和查询.
初始化容量(initial capacity): 创建hash表时桶的数量。
此外, hash表里还有一个"负载极限", 是一个0~1的数值, 决定了hash表的最大填满程度(当负载因子达到负载极限时, hash会自动成倍的增加容量(桶数), 并将原有对象重新分配, 称为"rehashing").

23. Java提供了一个操作Set、List和Map等集合的工具类: Collections, 该工具类提供了大量方法对集合元素进行排序、查询和修改等操作, 还提供了将集合对象设置为不可变、对集合对象实现同步控制等方法.

排序(对List):

- static void reverse(List list): 反转.

- static void shuffle(List list): 随机排序. (shuffle 方法模拟了"洗牌"动作. -->
* 所以那些播放器里的shuffle和repeat不同在于shuffle播放时随机但不重复(就只是洗乱顺序). )

- static void sort(List list): 根据元素的自然顺序对指定List集合的元素按升序排序.

- static void swap(List lit, int i, int j): 交换List的i处和j处元素.

- static void rotate(List list, int distance): distance为正时, 将所有元素整体向后平移distance个单位, 末尾的元素循环到list头; distance为负时, 向前平移.
查找和替换.
同步控制: Collections类中提供了多个synchronizedXxx()方法, 将指定集合包装称线程同步的集合, 从而解决多线程并发访问集合时的线程安全问题. (集合框架中常用的实现类HashSet、TreeSet、ArrayList、ArrayDeque、LinkedList、HashMap和TreeMap都是线程不安全的.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: