10. 集合

Collection

概述

在 java.util.Collection 中。是层级结构中的根接口,表示一组对象。Collection 是接口,但是在 JDK 中不提供此接口的任何实现,它提供了更为具体的子接口(如 Set,List)

Collection常用方法

集合中的 contains,remove 方法等涉及到对象比较的方法,都是用对象的 equals 方法。如果对象没有重写equals 方法,那么默认的 equals 方法的作用和 == 是一样的,都是比较对象的地址。

1. 添加

add(object obj): 一个添加一个元素

addAll(Collection other): 一次添加多个元素。理解为并集

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        // 多态。ArrayList 是 Collection 子接口 List 的实现类。
        Collection arrayList = new ArrayList();
        // 增加单个元素
        arrayList.add("张三");
        // 增加单个元素
        arrayList.add("李四");

        Collection other = new ArrayList();
        other.add("王五");
        other.add("赵六");

        // 增加另外一个 collection 集合。
        arrayList.addAll(other);

        System.out.println(arrayList.size()); // 4
    }
}
2. 删除

remove(object obj): 一次移出一个元素

removeAll(Collection other):一个移出多个元素。理解为移出多个相同的元素。

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四");
        arrayList.add("王五");
        System.out.println(arrayList.size());  // 3

        // 移出单个元素
        arrayList.remove("张三");
        System.out.println(arrayList.size());  // 2

        Collection other = new ArrayList();
        other.add("王五");
        other.add("赵六");

        // 一次移出多个元素。王五被移除
        arrayList.removeAll(other);
        System.out.println(arrayList.size());  // 1
    }
}

clear(): 清除所有元素

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四");
        arrayList.add("王五");

        arrayList.clear();  // 清空所有元素
        System.out.println(arrayList.size());
    }
}
3. 修改

Collection 根接口中没有提供修改的方法,子接口中可能有

4. 查询

contains(object obj): 判断 obj 是否在当前集合中

containsAll(Collection c): 判断 c 中的元素是否都在当前集合中

isEmpty(): 判断是否为空

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四");
        arrayList.add("王五");

        Collection other = new ArrayList();
        other.add("张三");
        other.add("田七");

        System.out.println(arrayList.contains("张三"));  // true
        System.out.println(arrayList.contains(other));  // false
    }
}

Collection 根接口中没有提供获取一个元素的方法。

5. 遍历

toArray: 如果该集合的底层是数组实现,那么效率较高,否则则较低。

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四");

        Object[] array = arrayList.toArray();
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}

foreach:可以称为增强版的 for 循环。如果只是查看数组或集合的元素,那么用 foreach 比较简单,如果涉及删除,修改,那么就不使用。

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四"); 
        arrayList.add("王五");

        for (Object object : arrayList) {
            System.out.println(object);
        }
    }
}

Iterator: 迭代器。在 java.util.Iterator。用于遍历和循环集合使用。只支持遍历 Collection 集合,不支持数组。

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四"); 
        arrayList.add("王五");

        Iterator iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            // iterator.next() 获取下一个元素。iterator.remove() 删除元素。
            Object object = (Object) iterator.next();
            System.out.println(object);
        }
    }
}
6. 其他

retainAll(Collection c):获取两个集合的交集

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        Collection arrayList = new ArrayList();
        arrayList.add("张三");
        arrayList.add("李四");
        arrayList.add("王五");

        Collection other = new ArrayList();
        other.add("张三");
        other.add("田七");

        arrayList.retainAll(other);
        System.out.println(arrayList.size());  // 1
    }
}

List

列表:可重复的,按顺序存储。也是接口,位置是 java.util.List

实现类:ArrayList(动态数组)

特点:
  1. 有序。可以使用索引精确的控制

  2. 可重复

常用方法:

因为是 Collection 的子接口,所有 Collection 有的方法,它都有。除此之外,还有很多和索引相关的方法。

add(index, Element): 在指定的 index 位置插入元素

addAll(index, Collection): 在指定的 index 位置插入多个元素。

remove(index): 删除指定位置的元素

set(index, Element): 修改指定位置的元素。collection 中是没有提供修改的方法的。

indexOf(object): 查询元素在集合中的位置,返回索引

lastindexOf(object): 查询元素在集合中的最后一个位置,返回索引

get(index): 返回 index 位置的元素

subList(fromIndex, toIndex): 截取,范围是 [fromIndex, toIndex)

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        List list = new ArrayList();
        list.add("张三");    // 父接口中的 add 方法
        list.add(0, "李四"); // list 中的 add方法,在指定位置插入元素

        List other = new ArrayList();
        other.add("王五");
        other.add("赵六");
        other.add(0, "李四");

        list.addAll(0, other);
        list.remove(0);
        list.set(0, "吴十");

        System.out.println(list.get(0));
        System.out.println(list.indexOf("吴十"));
        System.out.println(list.lastIndexOf("李四"));

        for (Object object : list) {
            System.out.println(object);
        }
    }
}

collection 中遍历集合中的元素有三种方法,分别是 for,foreach 和 Iterator。在 List 中还可以使用 ListIterator,它是 Iterator 的子接口,拥有 Iterator 的所有方法。除此之外遍历还可以指定方向,指定位置,还新增了 add 方法,set 方法等。

package com.itguigu.collection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.junit.Test;

public class TestConlection {
    @Test
    public void test1() {
        List list = new ArrayList();
        list.add("张三");    
        list.add(0, "李四"); 
        list.add("王五");
        list.add("赵六");
        list.add(0, "李四");

        // 从前往后遍历
        ListIterator listIterator = list.listIterator();
        while (listIterator.hasNext()) {
            Object object = (Object) listIterator.next();
            System.out.println(object);
        }

        System.out.println("---------------------");

        // 从后往前遍历,list.size() 用于指定遍历的开始位置
        ListIterator listIterator2 = list.listIterator(list.size());
        while (listIterator2.hasPrevious()) {
            Object object = (Object) listIterator2.previous();
            System.out.println(object);
        }

    }
}
常见实现类

Veactor: 动态数组,旧版本,线程安全的。内部实现为数组,初始化大小为 10。扩容时,扩容为原来的2倍。

ArrayList: 动态数组,新版本,线程安全的。内部实现为数组,初始化大小为 10。扩容时,扩容为原来的1.5倍。【使用频率较高】

LinkedList: 双向链表,双端队列。内部实现为链表。【使用频率较高】

Stack: 栈,Veactor 的子类。内部实现为数组。

package com.itguigu.collection;

import java.util.LinkedList;

import org.junit.Test;

public class TestList {
    @Test
    public void test() {
        LinkedList linkedList = new LinkedList();
        linkedList.offerFirst(1);  // 在前面添加元素
        linkedList.offerFirst(2);

        linkedList.offerLast(3);   // 在后面添加元素
        linkedList.offerLast(4);

        for (Object object : linkedList) {
            System.out.println(object);
        }
    }
}

动态数组和 LinkedList 的区别是什么?

  1. 内部实现不同,动态数组底层为数组。LinkedList 底层为链表
  2. 动态数组对索引相关的操作效率很高,LinkedList 则较低
  3. 动态数组的插入,删除涉及到元素的移动,LinkedList 的删除,插入只涉及到前后元素的关系。
  4. 如果是操作索引更多,那么可以选择动态数组。如果是添加删除,插入等操作,那么就选择链表。

Set

集:不可重复的,无序的(和添加顺序无关)。位置为 java.util.Set,是 Collection 的子接口

特点:
  1. 元素不重复
  2. 无序的(和添加顺序无关)
常见方法:

因为是 Collection 的子接口,所有 Collection 有的方法,它都有。Set 没有自己新增方法。

常见实现类:

HashSet:完全无序。保证元素不重复是靠对象的 equals 方法。所以在使用 HashSet 的时候需要重写对象的 equals 方法。

TreeSet: 可以按照大小排序,和添加顺序无关。保证元素不重复是靠 Comparable 接口的 compareTo 方法,或者其他的比较方法,例如 java.util.Comparator。例如两个李四都是 36 岁,但是第一个李四成绩为 99 分,第二个为 88 分。假如 compareTo 方法实现的功能是比较年纪,所以就认为这两个对象是相同的,那么第二个李四就不会添加进入集合当中。

LinkedHashSet:遍历的时候可以保证顺序是添加时候的顺序,但是存储和添加顺序无关。LinkedHashSet 是 HashSet 的子类,但是要比 HashSet 多维护一个添加的顺序,所以效率比 HashSet 要低。保证元素不重复是靠对象的 equals 方法。所以在使用 HashSet 的时候需要重写对象的 equals 方法。

package com.itguigu.collection;

import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.TreeSet;


import org.junit.Test;

public class TestList {
    @SuppressWarnings("all")
    @Test
    public void test() {
        // hashSet: 元素不重复
        HashSet hashSet = new HashSet();  
        hashSet.add("张三");
        hashSet.add("李四");
        hashSet.add("王五");
        hashSet.add("李四");

        for (Object object : hashSet) {
            System.out.println(object);  // 李四 张三 王五
        }
        System.out.println("-------------------");
    }

    @SuppressWarnings("all")
    @Test
    public void test2() {
        // treeSet:元素不重复,且可以排序,需要实现 Student compareTo 方法
        TreeSet treeSet = new TreeSet();  
        treeSet.add(new Student("张三", 99, 20)); 
        treeSet.add(new Student("李四", 80, 33));
        treeSet.add(new Student("王五", 76, 19));
        // 判断元素想不相同是使用 equals 方法,如果 Student 没有重写,那么默认和 == 一样。比较的是地址
        // 这里地址肯定是不一样的,所以 treeSet 中肯定有两个李四的对象
        // 所以我们需要实现 Student 的 hashCode 和 equals 方法。这样才不会有相同的 李四对象
        treeSet.add(new Student("李四", 80, 33)); 

        for (Object object : treeSet) {
            System.out.println(object);  
        }
        System.out.println("-------------------");
    }


    @SuppressWarnings("all")
    @Test
    public void test3() {
        // treeSet:传入自定义比较器
        TreeSet treeSet = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Student student1 = (Student) o1;
                Student student2 = (Student) o2;
                return student1.getAge() - student2.getAge();
            }
        });  
        treeSet.add(new Student("张三", 99, 20)); 
        treeSet.add(new Student("李四", 80, 33));
        treeSet.add(new Student("王五", 76, 19));
        treeSet.add(new Student("李四", 80, 33)); 

        for (Object object : treeSet) {
            System.out.println(object);  
        }
        System.out.println("-------------------");
    }

    @SuppressWarnings("all")
    @Test
    public void test4() {
        // LinkedHashSet:元素不重复,且顺序为添加时候的顺序
        LinkedHashSet linkedHashSet = new LinkedHashSet(); 
        linkedHashSet.add(new Student("李四", 80, 33));
        linkedHashSet.add(new Student("王五", 76, 19));
        linkedHashSet.add(new Student("张三", 99, 20)); 

        for (Object object : linkedHashSet) {
            System.out.println(object);  
        }
        System.out.println("-------------------");
    }
}


class Student implements Comparable{
    private String name;
    private int score;
    private int age;
    public Student(String name, int score, int age) {
        super();
        this.name = name;
        this.score = score;
        this.age = age;
    }
    public Student() {
        super();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(int score) {
        this.score = score;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", score=" + score + ", age=" + age + "]";
    }

    @Override
    public int compareTo(Object o) {
        Student student = (Student) o;
        // 按照成绩大小排序
        return this.score - student.score;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + score;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (score != other.score)
            return false;
        return true;
    }
}

结论:

  1. 如果既要元素不重复,又要可以支持大小排序,那么使用 TreeSet
  2. 如果既要元素不重复,又要保证添加顺序,那么可以使用 LinkedHashSet
  3. 如果只是需要元素不重复,那么 HashSet 既可。

Map

Java.util.Map接口与Collection 最大的不同就是 Map 存储的为 键值对。

Map常用方法

1. 添加

put(key, value)

putAll(Map map)

package com.itguigu.Map;

import java.io.BufferedWriter;
import java.util.HashMap;

public class TestMap {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        // 一次添加一个映射关系
        hashMap.put("key", "value");
        hashMap.put("key1", null);
        hashMap.put("key2", new String[] {"value1", "value2"});

        HashMap hashMap2 = new HashMap();
        hashMap2.put("key3", "value3");
        hashMap2.put("key4", "value4");

        // 一次添加多个映射关系
        hashMap.putAll(hashMap2);

        System.out.println(hashMap.size()); // 5
    }
}
2. 删除

remove(Object Key): 根据 key 删除

clear(): 清空

package com.itguigu.Map;

import java.util.HashMap;

public class TestMap {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        // 一次添加一个映射关系
        hashMap.put("key", "value");
        hashMap.put("key1", null);
        hashMap.put("key2", new String[] {"value1", "value2"});
        // remove
        hashMap.remove("key");
        System.out.println(hashMap.size());  // 2
        // clear
        hashMap.clear();
        System.out.println(hashMap.size());  // 0
    }
}
3.修改:

通过 put 可以替换 value

package com.itguigu.Map;

import java.util.HashMap;

public class TestMap {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        // 一次添加一个映射关系
        hashMap.put("key", "value");
        // put key 相同就等于替换
        hashMap.put("key", "new value");
    }
}
4. 查询

containsKey(Object key): 判断 key 是否存在

containsValue(Object value): 判断 value 是否存在

get(Object key): 根据 key 获取 value

isEmpty(): 判断是否为空

package com.itguigu.Map;

import java.util.HashMap;

public class TestMap {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        // 一次添加一个映射关系
        hashMap.put("key", "value");
        hashMap.put("key2", "value2");
        hashMap.put("key3", "value3");

        System.out.println(hashMap.containsKey("key3"));    // true
        System.out.println(hashMap.containsValue("value2"));// true
        System.out.println(hashMap.isEmpty());  // false
        System.out.println(hashMap.get("key")); // value
    }
}
5. 遍历:

keySet:获取 map 中的所有key,因为 key 不能重复,所以是一个 set。

values: 获取 map 的值。因为值可能是重复的,所以 values 返回的是 collection 类型。

entrySet:返回由 entry 对象构成的 set,因为 key 不会重复,所以 entry 对象也不会重复

package com.itguigu.Map;

import java.util.Collection;
import java.util.HashMap;
import java.util.Set;

public class TestMap {
    @SuppressWarnings("all")
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        // 一次添加一个映射关系
        hashMap.put("key", "value");
        hashMap.put("key2", "value2");
        hashMap.put("key3", "value3");

        // 获取所有的 key
        Set keySet = hashMap.keySet();
        for (Object object : keySet) {
            System.out.println(object);  // key2 key3 key
        }

        // 获取所有的 value
        Collection values = hashMap.values();
        for (Object object : values) {
            System.out.println(object); // value2 value3 value
        }

        // entrySet
        Set entrySet = hashMap.entrySet();
        for (Object object : entrySet) {
            System.out.println(object); // key2=value2 key3=value3 key=value
        }
    }
}

常见实现类

HashMap

Hashtable

LinkedHashMap:是 HashMap 的子类,比 HashMap 多维护了添加的顺序,也就是说添加是什么顺序,遍历就是什么顺序。

TreeMap:可根据 key 进行排序。所以key必须支持排序,即实现,java.lang.Comparable 接口,或者单独为 TreeMap 定制比较器。

Properties:是 hashtable 的子类,键和值都是字符串。

HashMap 和 Hashtable 的区别:Hashtable 是旧版本的,线程安全的,HashMap 是比 Hashtable 新的,是线程不安全的。Hashtable 的 key 和 value 都不允许为 null。HashMap 的 key 和 value 都允许为 null。


 本篇
10. 集合 10. 集合
Collection概述在 java.util.Collection 中。是层级结构中的根接口,表示一组对象。Collection 是接口,但是在 JDK 中不提供此接口的任何实现,它提供了更为具体的子接口(如 Set,List) Col
2019-10-27
下一篇 
9. StringBuffer 9. StringBuffer
StringBufferString 类型是不可变的字符序列,所以又配备了另一个类 StringBufer,它是可变的字符序列。StringBufer 有称为字符串缓冲区。内部用 char 数组存储。 StringBuffer 采用 ch
2019-10-24
  目录