java 集合类

    为了保存数目不确定的对象,JDK中提供了集合类(又称容器类),这些类可以存储任意类型的对象,并且长度可变,所有的集合类都位于java.util包中,在使用时需要导入该包,否则会出现异常。

Java集合类

集合按照存储结构可以分为两大类,分别是单列集合(Collection)双列集合(Map),这两种集合的特点如下所示:

  • Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是List和Set。其中,List的特点是元素有序,元素可重复;Set的特点是元素无序,而且不可重复。List接口的实现类有ArrayList和LinkedList,Set接口的主要实现类有HashSet环绕TreeSet。
  • Map:双列集合类的根接口,用于存储具有键(Key)、值(Value)映射关系的元素,每个元素都包含一对键值,在使用Map集合时可以通过指定的key找到对应的Value。Map接口的主要实现类有HashMap和TreeMap。 

List接口                                                                                                                             

  在List集合中可以出现相同的元素,所有的元素是以一种线性方式进行存储的,因此使用此集合能够精确地控制每个元素插入的位置,用户能够使用索引访问List中的元素。另外,List集合还有一个特点就是元素有序,即元素的存入和取出顺序一致。

ArrayList集合

  ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。

  ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
  ArrayList 实现了RandmoAccess接口,即提供了随机访问功能RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。

  ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。

  ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

 和Vector不同,ArrayList中的操作不是线程安全的!所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。

ArrayList的继承关系

java.lang.Object
   ↳     java.util.AbstractCollection<E>
         ↳     java.util.AbstractList<E>
               ↳     java.util.ArrayList<E>

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}

ArrayList API

 1 // Collection中定义的API
 2 boolean             add(E object)
 3 boolean             addAll(Collection<? extends E> collection)
 4 void                clear()
 5 boolean             contains(Object object)
 6 boolean             containsAll(Collection<?> collection)
 7 boolean             equals(Object object)
 8 int                 hashCode()
 9 boolean             isEmpty()
10 Iterator<E>         iterator()
11 boolean             remove(Object object)
12 boolean             removeAll(Collection<?> collection)
13 boolean             retainAll(Collection<?> collection)
14 int                 size()
15 <T> T[]             toArray(T[] array)
16 Object[]            toArray()
17 // AbstractCollection中定义的API
18 void                add(int location, E object)
19 boolean             addAll(int location, Collection<? extends E> collection)
20 E                   get(int location)
21 int                 indexOf(Object object)
22 int                 lastIndexOf(Object object)
23 ListIterator<E>     listIterator(int location)
24 ListIterator<E>     listIterator()
25 E                   remove(int location)
26 E                   set(int location, E object)
27 List<E>             subList(int start, int end)
28 // ArrayList新增的API
29 Object               clone()
30 void                 ensureCapacity(int minimumCapacity)
31 void                 trimToSize()
32 void                 removeRange(int fromIndex, int toIndex)
ArrayList API

ArrayList的toArray

  ArrayList提供了一个将List转为数组的一个非常方便的方法toArray。toArray有两个重载的方法:

  (1)list.toArray();

  (2)list.toArray(T[]  a);

  对于第一个重载方法,是将list直接转为Object[] 数组;

  第二种方法是将list转化为你所需要类型的数组,当然我们用的时候会转化为与list内容相同的类型。

 ArrayList 三种遍历方式

  (1)第一种,通过迭代器遍历。即通过Iterator去遍历。

Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

  (2) 第二种,随机访问,通过索引值去遍历。
由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

Integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {
    value = (Integer)list.get(i);        
}

  (3)第三种,foreach循环遍历。如下:

Integer value = null;
for (Integer integ:list) {
    value = integ;
}

 使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低

Set接口                                                                                                                                 

  Set接口主要有两个实现类,分别是HashSet和TreeSet。其中,HashSet是根据对象的哈希值确定元素在集合中的存储位置,因此具有良好的存取和查找性能。TreeSet是以二叉排序树的方式存储元素,他可以实现对几个元素进行排序。

HashSet集合

  HashSet结合之所以能确保不出现重复的元素,是因为在想Set中添加对象时,会西安调用次对象所在类的hashCode()方法,计算此对象的哈希值,次哈希值决定了此对象在Set中的存储对象,再通过equals()比较这两个对象是否相同,如果相同,则后一个对象就不能再添加进来。

Map接口                                                                                                                              

 HashMap集合

  HashMap集合是基于哈希表的Map接口的实现,它用于存储键值映射关系,但不保证映射的顺序。

  HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。

  HashMap 继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口
  HashMap 的实现不是同步的,这意味着它不是线程安全的。它的key、value都可以为null。此外,HashMap中的映射不是有序的。

  HashMap 的实例有两个参数影响其性能:“初始容量” 和 “加载因子”。容量 是哈希表中桶的数量,初始容量 只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,则要对该哈希表进行 rehash 操作(即重建内部数据结构),从而哈希表将具有大约两倍的桶数。
  通常,默认加载因子是 0.75, 这是在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询成本(在大多数 HashMap 类的操作中,包括 get 和 put 操作,都反映了这一点)。在设置初始容量时应该考虑到映射中所需的条目数及其加载因子,以便最大限度地减少 rehash 操作次数。如果初始容量大于最大条目数除以加载因子,则不会发生 rehash 操作。

HashMap的继承关系

java.lang.Object
   ↳     java.util.AbstractMap<K, V>
         ↳     java.util.HashMap<K, V>

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable { }

 (01) HashMap继承于AbstractMap类,实现了Map接口。Map是"key-value键值对"接口,AbstractMap实现了"键值对"的通用函数接口。 
(02) HashMap是通过"拉链法"实现的哈希表。它包括几个重要的成员变量:table, size, threshold, loadFactor, modCount。
  table是一个Entry[]数组类型,而Entry实际上就是一个单向链表。哈希表的"key-value键值对"都是存储在Entry数组中的。 
  size是HashMap的大小,它是HashMap保存的键值对的数量。 
  threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量。threshold的值="容量*加载因子",当HashMap中存储数据的数量达到threshold时,就需要将HashMap的容量加倍。
  loadFactor就是加载因子。 
  modCount是用来实现fail-fast机制的。

HashMap的整体结构

简单来说,HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

 HashMap遍历方式

  (1) 遍历HashMap的键值对

第一步:根据entrySet()获取HashMap的“键值对”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

 1 // 假设map是HashMap对象
 2 // map中的key是String类型,value是Integer类型
 3 Integer integ = null;
 4 Iterator iter = map.entrySet().iterator();
 5 while(iter.hasNext()) {
 6     Map.Entry entry = (Map.Entry)iter.next();
 7     // 获取key
 8     key = (String)entry.getKey();
 9         // 获取value
10     integ = (Integer)entry.getValue();

  (2)遍历HashMap的键

第一步:根据keySet()获取HashMap的“键”的Set集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是HashMap对象
// map中的key是String类型,value是Integer类型
String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
        // 获取key
    key = (String)iter.next();
        // 根据key,获取value
    integ = (Integer)map.get(key);

  (3)遍历HashMap的值

第一步:根据value()获取HashMap的“值”的集合。
第二步:通过Iterator迭代器遍历“第一步”得到的集合。

// 假设map是HashMap对象
// map中的key是String类型,value是Integer类型
Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

Properties集合

  Properties主要用于存储字符串类型的键和值,由于Properties类实现了Map接口,因此,Properties类本质上是一种简单的Map集合。在实际开发中,经常使用Properties几个存取应用的配置项。

(1)setProperty ( String key, String value) ,调用 Hashtable 的方法 put 。他通过调用基类的put方法来设置 键 - 值对。

(2)getProperty ( String key),用指定的键在此属性列表中搜索属性。也就是通过参数 key ,得到 key 所对应的 value。

(3) load ( InputStream inStream),从输入流中读取属性列表(键和元素对)。通过对指定的文件进行装载来获取该文件中的所有键 - 值对。以供 getProperty ( String key) 来搜索。

(4)store ( OutputStream out, String comments),以适合使用 load 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。与 load 方法相反,该方法将键 - 值对写入到指定的文件中去。

(5) clear (),清除所有装载的 键 - 值对。该方法在基类中提供。

Collection 和 Collections的区别:

  Collection是一个集合的接口。它提供了对集合对象进行基本操作的通用方法。实现该接口的类主要有List和Set,该接口的设计目标是为各种具体的集合提供最大化的同一操作方式。

  Collections是针对集合类的一个包装类,它提供了一系列静态方法实现对各种集合的搜索、排序以及线程安全等操作,其中大部分方法用于处理线性表。Collection类不能实例化,如同一个工具类,服务于Collection框架。如果在使用Collections类的方法时,对用Collection的对象null,则这些方法都会抛出NullPointException。

参考:

http://www.cnblogs.com/skywang12345/p/3308556.html

http://www.cnblogs.com/skywang12345/p/3310835.html

https://www.cnblogs.com/chengxiao/p/6059914.html

2018-10-03 20:46:17

原文地址:https://www.cnblogs.com/qqiua/p/9740734.html