JAVA集合详解

1,253 阅读11分钟

体系结构(将一般较多使用的划分出来)

1.为什么要需要Collection?

java是一种面向对象的语言,为了方便处理多个对象,把多个对象储存起来,需要一个容器-----集合。

2.数组和集合的区别?

  • 长度: 数组的长度固定,集合的长度可变。
  • 内容: 数组储存的同一类型的元素,集合可以储存不同的元素,但是我们通常不那样做。
  • 元素的数据类型: 数组可以储存基本数据类型和引用类型,集合只能储存引用类型。

3.集合类简介

Java集合大致可以分为Set、List、Queue和Map四种体系,其中Set代表无序、不可重复的集合;List代表有序、重复的集合;而Map则代表具有映射关系的集合,Java 5 又增加了Queue体系集合,代表一种队列集合实现。 Java集合就像一种容器,可以把多个对象(实际上是对象的引用,但习惯上都称对象)“丢进”该容器中。从Java 5 增加了泛型以后,Java集合可以记住容器中对象的数据类型,使得编码更加简洁、健壮。

4.Collection接口

4.1简介:

collection接口是set,Queue,List的父接口

4.2使用Iterator遍历集合元素

Iterator接口是Collection的父接口,主要用于遍历Collection中的元素,其中定义了两个方法

Iterator的使用

public class IteratorExample {
    public static void main(String[] args){
        //创建集合,添加元素  
        Collection<Day> days = new ArrayList<Day>();
        for(int i =0;i<10;i++){
            Day day = new Day(i,i*60,i*3600);
            days.add(day);
        }
        //获取days集合的迭代器
        Iterator<Day> iterator = days.iterator();
        while(iterator.hasNext()){//判断是否有下一个元素
            Day next = iterator.next();//取出该元素
            //逐个遍历,取得元素后进行后续操作
            .....
        }
    }

}

注意: 使用Iterator对集合元素进行遍历时,Iterator并不是把集合元素本身传递给迭代变量,而是把集合元素的值传递给了迭代变量。

4.3ArrayList和Vector

ArrayList和Vector都是动态扩展的数组,如果开始的时候知道集合容纳元素的数量,可以指定initialCapacity的大小,这样可以提到性能。

**区别:**ArrayList线程不安全,Vector线程是安全的。Vector性能比ArrayList差。

Stack 是Vector的子类,先进后出,线程是安全的,但是性能较差,

ArrayList的遍历方法:

  • 使用迭代器遍历
Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}
  • 随机访问通过索引值去访问
 Integer value = null;
int size = list.size();
for (int i=0; i<size; i++) {
    value = (Integer)list.get(i);        
}
  • for循环访问
Integer value = null;
for (Integer integ:list) {
    value = integ;
}

4.4LinkedList

LinkedList是List是实现类,说明其可以通过索引来随机访问集合中的元素,除此之外,LinkedList还实现了Deque接口,还可以被当做双端队列来使用。 LinkedList与ArrayList完全不同,ArrayList以数组的形式来保存集合中的元素;而LinkedList内部以链表的形式保存集合的元素,因此随机访问的性能较差,但是插入和删除元素时的性能较出色。

##4.41LinkedList方法

void addFirst(E e):将指定元素插入此列表的开头。
void addLast(E e): 将指定元素添加到此列表的结尾。
E getFirst(E e): 返回此列表的第一个元素。
E getLast(E e): 返回此列表的最后一个元素。
boolean offerFirst(E e): 在此列表的开头插入指定的元素。
boolean offerLast(E e): 在此列表末尾插入指定的元素。
E peekFirst(E e): 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
E peekLast(E e): 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
E pollFirst(E e): 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
E pollLast(E e): 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
E removeFirst(E e): 移除并返回此列表的第一个元素。
boolean removeFirstOccurrence(Objcet o): 从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表时)。
E removeLast(E e): 移除并返回此列表的最后一个元素。
boolean removeLastOccurrence(Objcet o): 从此列表中移除最后一次出现的指定元素(从头部到尾部遍历列表时)。

4.42遍历方法

1.通过迭代器遍历LinkedList 2通过快速随机访问遍历LinkedList 3.通过for循环遍历LinkedList 4.通过pollFirst()遍历LinkedList 5.通过pollLast()遍历LinkedList 6通过removeFirst()遍历LinkedList 7.通过removeLast()遍历LinkedList 实现都比较简单,就不贴代码了。

5.set集合

set集合和Collection集合基本相同,没有提供额外的方法,set不允许包含相同的元素,试图把两个相同的元素放到一个集合中,add()方法会返回false。

5.1HashSet

##5.11 HashSet的特点

  • 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化
  • HashSet不是同步的,如果多线程访问需要保证其同步
  • 集合元素可以是null
  • 判断两个元素是否相等,判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法的返回值也相等。

equals()和hashCode()

equals() 比较两个对象是不是同一个对象

hashCode() 作用是获取哈希码,实践上是返回一个int整数,这个哈希码的作用是确定该对象在哈希表中的位置。Object类的默认的hashCode(),可以用来比较两个对象是否是同一个对象。 HashSet中元素的比较

  • equals()返回false,hashCode()返回值不相等,HashSet会把他们保存在不同的位置。
  • equals()返回true,hashCode()返回值不相等,,HashSet会把他们保存在不同的位置。
  • equals()返回false,hashCode()返回值不相等,,HashSet会把他们保存在相同的位置。会在这个位置以链表结构保存多个对象,这是因为当向HashSet集合中存入一个元素时,HashSet会调用对象的hashCode()方法来得到对象的hashCode值,然后根据该hashCode值来决定该对象存储在HashSet中存储位置。
  • 如果有两个元素通过equal()方法比较返回true,但它们的hashCode()方法返回true,HashSet将不予添加

5.2TreeSet

保证集合元素处于排序状态

5.21TreeSet的方法

comparator():返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回null。
first():返回此 set 中当前第一个(最低)元素。
last(): 返回此 set 中当前最后一个(最高)元素。
lower(E e):返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null。
higher(E e):返回此 set 中严格大于给定元素的最小元素;如果不存在这样的元素,则返回 null。
subSet(E fromElement, E toElement):返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)。
headSet(E toElement):返回此 set 的部分视图,其元素小于toElement。
tailSet(E fromElement):返回此 set 的部分视图,其元素大于等于 fromElement。

5.22TreeSet的排序方式

支持两种排序方式,自然排序(默认);定制排序

5.23TreeSet判断集合元素相等

唯一标准,两个对象通过compareTo(Object obj),通过compareTo(Object obj)方法比较返回0,TreeSet则会认为它们相等,不予添加入集合内;否则就认为它们不相等,添加到集合内。

6.List集合

List集合代表了一个元素有序可重复的集合,集合的每个元素都有其索引,List集合允许使用重复的元素。默认按添加元素的顺序设置元素的索引。相比Collection接口的全部方法,List中添加了一些根据索引操作集合的方法。

void add(int index, Object element): //在列表的指定位置插入指定元素(可选操作)。
boolean addAll(int index, Collection<? extends E> c) :  将集合c 中的所有元素都插入到列表中的指定位置index处。
Object get(index):返回列表中指定位置的元素。
int indexOf(Object o): 返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
int lastIndexOf(Object o):返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
Object remove(int index); 移除列表中指定位置的元素。
Object set(int index, Object element):用指定元素替换列表中指定位置的元素。
List subList(int fromIndex, int toIndex): 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的所有集合元素组成的子集。
Object[] toArray(): 返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。

java8中还添加了两个默认方法

void replaceAll(UnaryOperator operator):根据operator指定的计算规则重新设置List集合的所有元素。
void sort(Comparator c):根据Comparator参数对List集合的元素排序。

7.Queue集合

Queue用户模拟队列这种数据结构,队列通常是指“先进先出”(FIFO,first-in-first-out)的容器。队列的头部是在队列中存放时间最长的元素,队列的尾部是保存在队列中存放时间最短的元素。新元素插入(offer)到队列的尾部,访问元素(poll)操作会返回队列头部的元素。通常,队列不允许随机访问队列中的元素。

8.Map集合

8.1简介

Map保存具有映射关系的数据,因此Map集合中保存着两组数,Key和Value都是可以支持任何数据类型的数据,Map中的key不允许重复,key和value存在一对一的对应关系。

8.2Map集合与Set和List的关系

  • 和set集合的关系,把Map的所有Key放在一起,可以看成一个set集合
  • 和List集合的关系,把Map的所有value放在一起看,可以看成一个List集合

8.3使用

public class MapTest {
    public static void main(String[] args){
        Day day1 = new Day(1, 2, 3);
        Day day2 = new Day(2, 3, 4);
        Map<String,Day> map = new HashMap<String,Day>();
        //成对放入key-value对
        map.put("第一个", day1);
        map.put("第二个", day2);
        //判断是否包含指定的key
        System.out.println(map.containsKey("第一个"));
        //判断是否包含指定的value
        System.out.println(map.containsValue(day1));
        //循环遍历
        //1.获得Map中所有key组成的set集合
        Set<String> keySet = map.keySet();
        //2.使用foreach进行遍历
        for (String key : keySet) {
            //根据key获得指定的value
            System.out.println(map.get(key));
        }
        //根据key来移除key-value对
        map.remove("第一个");
        System.out.println(map);
    }

}

8.4 HashMap

HashMap是一个散列表,它存储的内容是键值对(Key-value)映射 **与Hashtable的比较:**HashMap比Hashtable的性能要好一些,但是线程不安全。 Hashtable不允许null作为key或value,但是HashMap可以使用null作为key或者value。

8.41判断相等的标准

key和hashset比较像,hashCode()返回结果一直,equals()返回true。 value equals()返回结果为true。

8.42HashMap的本质

HashMap的构造函数

// 默认构造函数。
HashMap()

// 指定“容量大小”的构造函数
HashMap(int capacity)

// 指定“容量大小”和“加载因子”的构造函数
HashMap(int capacity, float loadFactor)

// 包含“子Map”的构造函数
HashMap(Map<? extends K, ? extends V> map)

有两个重要的元素:容量(capacity)和加载因子(loadFactor),加载因子是在其容量自动增加之前可以达到多满的程度(通常默认为0.75)

Node类型 HashMap是通过“拉链法”实现的哈希表,它包括几个重要的成员变量:table,size,threshold,loadFactor size 是HashMap的大小,它是HashMap保存的键值对的数量。threshold是阈值,用于判断是否需要调整HashMap的容量,threshold的值=size*loadFactor,当存储的数据达到数量时,就将HashMap的容量加倍。

**数据存储方式:**综合了数组和链表的优点-----哈希表,有较快的查询速度和增删速度,通过hash(key)获得key的哈希值,如果hash值相等,则都存入该hash值对应的链表中,其内部是通过一个node数组来实现的,每一个数组元素代表一个链表,其共同点就是hash(key)相等

Node基本元素

static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        // 指向下一个节点
        Node<K,V> next;
        //构造函数。
      // 输入参数包括"哈希值(hash)", "键(key)", "值(value)", "下一节点(next)"
        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
         // 判断两个Node是否相等
        // 若两个Node的“key”和“value”都相等,则返回true。
        // 否则,返回false
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

HashMap的遍历方式

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

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

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

##8.5TreeMap