集合类
一、集合类体系结构
【注意】:
(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)遍历格式:
(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)删:
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)常用方法:
【tips】:①逆向遍历时使用while-hasPrevious()-hasNext()组合;
next() |
返回列表中的下一个元素 |
hasNext() |
判断迭代器中是否还有元素 |
previous() |
返回列表中的上一个元素 |
hasPrevious() |
判断迭代器中是否还有元素 |
add() |
将指定的元素插入列表 |
②一般使用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时,表示二者相等;
(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() |
返回集合中的键值对的对数(即集合长度) |
3.获取操作
V get(Object key) |
根据键,返回值;没有该键的映射就返回null |
Set<K> keySet() |
返回包含所有键的Set集合 |
Collection<V> values() |
返回包含所有值的Collection集合 |
Set<Map.Entry<K,V>> entrySet() |
返回包含所有整个键值对对象的Set集合 |
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集合。 |
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) |
使用默认的随机源随机排列指定的列表。 |