一、集合类体系结构

【注意】:
(1)List中元素可重复,Set中元素不可重复;
(2)表示接口,表示对应的实现类。

二、Collection

1.创建对象

Collection<E> c = new ArrayList<>();//因为Collection是一个接口,所以采用多态的方式创建对象
【tips】:<E>里是引用类型,当元素数据类型为基本数据类型时,<E>要用对应的包装类类型。

2.常用操作

(1)增:
boolean add(E e)//将指定的元素追加到此列表的末尾
(2)删:
boolean remove(Object o)//从该集合中删除指定元素
(3)置空:
void clear()//清空集合所有元素
(4)查:
boolean contains(Object o)//如果此集合包含指定的元素,则返回true。
(5)判空:
boolean isEmpty()//如果此集合没有任何元素,则返回true。
(6)获取集合长度:
int size()//返回此列表中的元素个数。

3.遍历

(1)Iterator(迭代器):是集合专用的遍历方式,通过以下代码得到:
Iterator<E> it = 集合对象.iterator();
(2)方法:
    1)E next():返回迭代器中的下一个元素。
    2)boolean hasNext():判断是否还有元素。
(3)遍历格式:
while(it.hasNext()){
    E e = it.next();
    System.out.println(e);
}

三、List

1.概述

    List是一个有序集合(也叫序列),可以通过整数索引(从0开始)访问元素。与Set不同,List允许重复的元素。

2.特点

(1)有序:存储和取出的元素顺序一致。
(2)可重复:存储的元素可以重复。

3.常用操作

(1)增:
public boolean add(E e)//将指定的元素追加到此列表的末尾
public void add(int index,E element)//在此列表中的指定位置插入指定的元素。 将当前位于该位置的元素(如果有)和后续元素向后移动。
(2)删:
public E remove(int index)//删除该列表中指定位置的元素。
public boolean remove(Object o)//从列表中删除第一个出现的指定元素(如果存在)。
(3)改:
public E set(int index, E element)//用指定的元素替换此列表中指定位置的元素。
(4)查:
public E get(int index)//返回此列表中指定位置的元素。
(5)获取列表长度(即元素个数)
public int size()//返回此列表中的元素个数。

4.并发修改异常(ConcurrentModificationException)

(1)异常原因:在调用.next()方法时,先调用checkForComodification()判断实际修改集合次数是否等于预期修改集合次数,如果二者不相等,就抛出并发修改异常ConcurrentModificationException
public class ArrayList<E> implements List<E>{
   
    protected transient int modCount = 0;//实际修改集合次数
    
    public boolean add(E e) {
        modCount++;//每调用一次add添加元素,实际修改集合次数+1
        add(e, elementData, size);
        return true;
    }
    
    private class Itr implements Iterator<E> {
     
        int expectedModCount = modCount;//预期修改集合次数

        public boolean hasNext() {
            return cursor != size;
        }

        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        final void checkForComodification() {
            //如果实际修改集合次数不等于预期修改集合次数,就抛出异常
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
}
(2)处理方案:
    采用for循环的形式代替while循环+Iterator进行遍历,用get()获取元素而不是.next()。

5.ListIterator(列表迭代器)

        通过.listIterator()获得,是List特有的迭代器。允许沿任一方向(正向逆向)遍历列表的列表的迭代器。
(1)常用方法:
next()
返回列表中的下一个元素
hasNext()
判断迭代器中是否还有元素
previous()
返回列表中的上一个元素
hasPrevious()
判断迭代器中是否还有元素
add() 将指定的元素插入列表
【tips】:①逆向遍历时使用while-hasPrevious()-hasNext()组合;
                ②一般使用Iterator进行遍历操作;
                ③使用ListIerator中的add()可以不触发并发修改异常,因为在add()中,把modCount赋给expectedModCount了,二者必相等,再调用.next()时就不会抛出ConcurrentModificationException。
public void add(E e) {
    checkForComodification();

    try {
        int i = cursor;
        ArrayList.this.add(i, e);
        cursor = i + 1;
        lastRet = -1;
        expectedModCount = modCount;//保证实际修改次数等于期望修改次数
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
        }

6.三种遍历方式

(1)while-hasNext()-next()遍历:
while(it.hasNext()){
    E e = it.next();
    System.out.println(e);
}
(2)for-size()-get(index)遍历:
(3)增强for循环:简化数组和Collection集合的遍历。
    1)格式:
for(元素数据类型 变量名:数组名/Collecton集合){
    ...;
}
    2)eg1:
int[] arr = {1, 2, 3}; for (int i : arr) {
    System.out.println(i); }
        eg2:
String[] strArr = {"hello", "world", "java"};
for (String s : strArr) {
    System.out.println(s);
}
        eg3:
List<String> l = new ArrayList<>();
l.add("Hohai");
l.add("University");
for (String str : l) {
    System.out.println(str);
}

四、List两个常用子类——ArrayList和LinkedList

(一)ArrayList

1.特点

        底层实现是数组,查询快,增删慢。

2.常用操作

    同List。

(二)LinkedList

1.特点

        底层实现是链表,增删快,查询慢。

2.常用操作

(1)同List。
(2)LinkedList特有的方法:
public void addFirst(E e)
在该列表开头插入指定的元素。
public void addLast(E e)
将指定的元素追加到此列表的末尾。
public E removeFirst()
从此列表中删除并返回第一个元素。
public E removeLast()
从此列表中删除并返回最后一个元素。
public E getFirst()
返回此列表中的第一个元素。
public E getLast()
返回此列表中的最后一个元素。

五、Set

1.概述

        Set集合是不能存储重复元素的无序集合(存储和取出的顺序不一致),不含带索引的方法,所以不能用for-size-get(index)遍历。

2.特点

(1)元素唯一性
(2)无序
(3)无索引

六、两个Set常用子类——HashSet和TreeSet

(一)HashSet

1.概述

底层实现是哈希表,是不能存储重复元素的无序集合不含带索引的方法,所以不能用for-size-get(index)遍历。

2.哈希值

        是JDK根据对象的地址/字符串/数字算出来的int类型的数值。
(1)对象哈希值的获取:Object类中的hashCode()可以返回对象的哈希值。
(2)对象哈希值的特点:
    1)同一对象多次调用hashCode()返回的哈希值是一样的;
    2)一般情况下,不同对象的哈希值是不同的;
    3)重写hashCode()可以使不同对象的哈希值相同。

3.HashSet保证元素唯一性分析


【tips】:要保证元素唯一性,需要重写hashCode()equals()

4.LinkedHashSet

(1)概述:是HashSet的子类,底层由哈希表和链表实现,是不能存储重复元素的有序集合。
(2)特点:
    1)元素唯一性:由哈希表实现;
    2)有序:由链表实现。

(二)TreeSet

1.特点

(1)元素有序,这里的有序不是指存取顺序一致,而是指按照一定的规则排序,具体排序方法取决于使用的构造方法;
(2)元素唯一性;
(3)没有索引。

2.构造方法

(1)TreeSet():根据元素的自然序列(比如数字的自然序列就是从小到大排序)进行排序;
(2)TreeSet(Comparator comparator):根据指定的比较器(comparator进行比较。
【tips】:“自然序列”不是指元素存储时的顺序!

3. Comparable接口的使用

(1)该接口对它的实现类对象强加一个整体排序;
(2)用TreeSet的无参构造创建的对象,存储元素时使用的是自然排序,此时需要对元素所在的类实现Comparable接口重写compareTo(T  o)方法;
(3)int compareTo(T o)方法返回值规则:当return一个正整数时,表示对象o调用compareTo方法的对象大;当return一个负整数时,表示o比调用对象小;当return返回0时,表示二者相等;

(4)重写compareTo方法时要注意排序规则的主、次要条件。

4. 比较器排序Comparator的使用

(1)用TreeSet存储自定义对象时,带参构造方法使用的是比较器排序对元素进行排序;
(2)比较器排序就是让TreeSet集合的带参构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法;
(3)重写compare方法时要注意排序规则的主、次要条件。
【tips】:①类名或接口名作形参时,实际需要接收的是继承该类的子类对象或实现该接口的实现类对象,而匿名内部类的本质就是一个对象,因此可以直接在()里new一个匿名内部类;
                 ②o1是新添加的元素。

七、泛型

1.概述

        泛型提供了在编译时类型安全监测机制,允许在编译时监测到非法的类型。泛型的本质是参数化类型,即所操作的数据类型被指定为一个参数,把原来具体的类型参数化,在使用或调用时再传入具体的类型。

2.优点

(1)避免了强制类型转换:不使用泛型时数据类型默认是Object类型,想使用具体的数据类型时就要进行强制类型转换,而泛型的使用就避免了这种强制类型转换;
(2)把运行时才会发现的问题(ClassCastException)提前到了在编译期间就可以被发现:当使用了泛型后,在编译再添加泛型外的类型时,会直接报错。

3.分类

        泛型类、泛型方法、泛型接口
(1)泛型类:
    1)定义格式:
修饰符  class  类名 <类型>{}
    2)eg:
public class Generic<T>{
    private T t;
    
    public T getT(){
        return t;
    }
    
    public void setT(T t){
        this.t = t;
    }
}
把原来具体的类型参数化,在使用或调用时再传入具体类型”:在创建Generic类的对象时,<>里可以填任意想用的数据类型。
GenericClass<String> gc = new GenericClass<>();
gc.setT("hello");
System.out.println(gc.getT());//"hello"

GenericClass<Integer> gc2 = new GenericClass<>();
gc2.setT(100);
System.out.println(gc2.getT());//100

GenericClass<Boolean> gc3 = new GenericClass<>();
gc3.setT(true);
System.out.println(gc3.getT());//true
(2)泛型方法:
定义格式:修饰符  <类型>  返回值类型  方法名(类型  类型名)
(3)泛型接口:
定义格式:修饰符  interface  接口名  <类型> {}
【注意】:泛型接口的实现类也要写成泛型类的形式。

4.类型通配符<?>

(1)List<?>:表示元素可以是任意类型的List;
List<?> l1=new ArrayList<Object>();
List<?> l2=new ArrayList<Number>();
List<?> l3=new ArrayList<Integer>();
【注意】:这种带通配符的List仅仅代表它是各种泛型List的父类,并不能把元素添加到其中。
(2)类型通配符上限:List<? extends Number>只能表示Number或Number的子类;
//List<? extends Number> l4=new ArrayList<Object>();//报错,Object超出了类型通配符上限 List<? extends Number> l5=new ArrayList<Number>(); List<? extends Number> l6=new ArrayList<Integer>();
(3)类型通配符下限:List<? super Number>只能表示Number或Number的父类。
List<? super Number> l7=new ArrayList<Object>();
List<? super Number> l8=new ArrayList<Number>();
//List<? super Number> l9=new ArrayList<Integer>();//报错,Integer超出了类型通配符的下限
【tips】:Integer extends Number extends Object

5.可变参数

(1)可变参数:作为方法的形参,形参个数可变。
(2)定义格式:修饰符 返回值类型 方法名(数据类型...  变量名){}
【tips】:①这些可变的参数被封装在一个数组里了,所以这里的变量名其实是一个数组名;
                ②当包含可变参数的多个参数作形参时,可变参数要放在最后。
public int sum(int b,int... a)
//public int sum(int... a,int b)//报错
(3)可变参数的使用:
    1)Arrays工具类中有一个静态方法:
public static <T> List<T> asList(T... a)//返回由指定数组支持的固定大小的List列表。
【注意】:通过asList返回的List集合不能进行增删操作,可以进行修改(set)操作。
    2)List接口中有一个静态方法:
static <E> List<E> of(E... elements)//返回包含任意数量元素的不可变List列表。
【注意】:通过of返回的List集合不能进行增删改操作。
    3)Set接口中有一个静态方法:
static <E> Set<E> of(E... elements)//返回包含任意数量元素的不可变Set集合。
【注意】:通过of返回的Set集合不能进行增删操作。(Set没有索引,本来就不能调用set()方法)

八、Map

1.概述

        interface Map<K,V>    K:键的类型,V:键映射的值的类型
【注意】:①键是唯一的;②键与值一一对应;③使用多态的方式创建Map对象

2.常用操作

V put(K key,V value)
添加键值对元素
V remove(Object key)
根据指定键删除该键值对元素,并返回该键映射的值
boolean containsKey(Object key)
判断集合中是否有指定键
boolean containsValue(Object value)
判断集合中是否有指定值
void clear()
删除所有的键值对元素
boolean isEmpty()
判断集合是否为空
int size()
返回集合中的键值对的对数(即集合长度)
【tips】:使用put(K key,V value)添加键值对元素时,如果键重复,则新值会替代该键映射的旧值。

3.获取操作

V get(Object key)
根据键,返回值;没有该键的映射就返回null
Set<K> keySet()
返回包含所有键的Set集合
Collection<V> values()
返回包含所有值的Collection集合
Set<Map.Entry<K,V>> entrySet()
返回包含所有整个键值对对象的Set集合
【tips】:Map.Entry<K,V>是一个接口,可通过它的getKey()和getValue()方法来分别获取键和值。

4.遍历

(1)keySet-增强for-get遍历:
思路:先获取所有键,再获取每个键,最后根据每个键获取值。
//获取所有键
Set<String> keySet = m.keySet();
//获取每一个键
for (String key : keySet) {
    //根据键找值
    String value = m.get(key);
    //输出键值对
    System.out.println(key + "--" + value);
(2)entrySet-增强for-getKey/Value遍历
思路:先获取所有的键值对,再获取每一对键值对,最后分别获取键和值并输出。
//获取所有的键值对
Set<Map.Entry<String, String>> kv = m.entrySet();
//获取每一对键值对
for (Map.Entry<String, String> me : kv) {
    //分别获取键和值并输出
    String key = me.getKey();
    String value = me.getValue();
    System.out.println(key + "-" + value);
}
【tips】:这两种遍历方式中,获取每个键和获取每对键值对用的都是增强for。

5.Properties

(1)概述:Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串
    public class Properties extends Hashtable<Object,Object>:Properties继承了Hashtable ,是Map体系下的集合,但不建议使用Map集合的方法,因为Properties有自己特有的方法。
【注意】:Properties虽然继承了Hashtable<Object,Object>,但它没有使用泛型,因为属性列表中的每个键及其对应的值都是字符串类型
(2)特有方法:
Object setProperty(String key, String value)
向Properties对象中添加一个都是String类型的键值对。(代替put方法)
String getProperty(String key) 获取指定键对应的值。
Set<String> stringPropertyNames() 获取一个存有所有键的Set集合。
(3)Properties与IO流结合的方法(load和store):
void load(InputStream inStream)
从字节输入流读取键值对,可用来通过字节输入流把文件中的键值对存入Properties集合。
void load(Reader reader)
从字符输入流读取键值对,可用来通过字符输入流把文件中的键值对存入Properties集合。
void store(OutputStream out, String comments)
将键值对写入字节输出流,可用来将Properties集合中的键值对通过字节输出流写入文件。
void store(Writer writer, String comments)
将键值对写入字符输出流,可用来将Properties集合中的键值对通过字符输出流写入文件。

九、Collections工具类

1.概述

        Collections是针对集合操作的工具类。

2.常用方法

public static <T> void sort(List<T> list,Comparator<? super T> c)
根据其元素的自然排序,将指定的列表按升序排序
public static void reverse(List<?> list)
反转list列表中元素的顺序。
public static void shuffle(List<?> list)
使用默认的随机源随机排列指定的列表。
【注意】:sort方法使用了比较器Comparator,如果元素不是Comparator的实现类,需要在类中重写compareTo()方法或直接采用匿名内部类的方式。