9. Java集合

1. Java集合框架概述

1.1 集合和数组

  • Java中对多个对象进行存储时,若使用Array则有很多弊端,而Java集合可以动态地把多个对象的引用放入容器中。
  • 使用数组存储对象的弊端:① 一旦创建,长度不可变;② 数组中存放的对象个数不可知,需要自行设变量记录所存储对象的个数;③数组中提供的方法非常有限,对添加、删除、插入等操作非常不便,效率不高。

1.2 集合的分类
Java集合可分为Collection和Map两种体系,集合中存储基本数据类型时为包装类。

  • Collection接口:单列数据,定义了存储一组对象的方法的集合。有List和Set等多种子接口。
    • List接口:元素有序、可重复的集合。(又称作动态数组)
    • Set接口:元素无序、不可重复的集合。
  • Map接口:双列数据,保存具有映射关系的“key-value对”集合。

在这里插入图片描述
在这里插入图片描述

2. Collection接口方法

  • add(Object e):添加元素e到集合中(对基本数据而言,e为包装类)
  • size():获取集合中元素的个数
  • addAll(Collection c):将集合c中所有元素添加到当前集合中
  • isEmpty():判断当前集合是否为空
  • clear():清空集合元素
  • contains(Object e):判断当前集合中是否包含e,通过equals()方法进行判断
  • containsAll(Collection c):判断集合c中的所有元素是否都在当前集合中
  • remove(Object e):删除集合中的元素e,返回boolean类型
  • removeAll(Collection c):从当前集合中移除集合c中的所有元素(两集合求差)
  • retainAll(Collection c):两集合求交,返回当前集合
  • equals(Collection c):判断两集合是否相同
  • hashCode():返回当前集合的哈希值
  • toArray():将集合转化为数组
  • Arrays.asList(Array a):将数组a转为List
  • iterator():返回一个Iterator接口的实例,用于遍历集合元素

3. Iterator迭代器接口

  • 使用Iterator接口实现集合元素的遍历,Iterator对象成为迭代器,是设计模式中的一种。
  • 迭代器模式提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节。(类似于公交车售票员)
  • Collection接口继承了java.lang.Iterator接口,该接口有一个iterator()方法。
  • Iterator仅用于遍历集合,Iterator本身并没有承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。
  • 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标在集合的第一个元素之前。
Iterator<Object> iterator = list.iterator();
while (iterator.hasNext()) {
    
    
    System.out.println(iterator.next());
}
  • hasNext()方法判断指针下一处是否有元素
  • next()方法将指针下移一位
  • remove()方法删除集合中指针所指的元素(这是迭代器对象的remove方法,与集合中的remove方法不同)

foreach循环遍历集合或数组
Java 5.0提供了foreach循环(增强for循环)访问Collection和数组,内部使用Iterator循环。

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

4. Collection子接口一:List

4.1 List的常用实现类

  • 鉴于Java中数组存储数据的局限性,常用List替代数组
  • List接口的常用实现类有:ArrayList、LinkedList、Vector
  • ArrayList:作为List接口的主要实现类,线程不安全,效率高。底层使用Object[]数组存储,jdk7中,空参构造器初始化容量为10的数组,当数组容量不够时扩容为原来的1.5倍,建议使用带参构造器;jdk8中,空参构造器初始化不创建数组,当添加元素时才创建长度为10的数组,其他操作与jdk7相同。
  • LinkedList:底层使用双向链表存储。对频繁的插入、删除操作效率高。内部声明了Node类型的first和last属性,默认值为null,添加元素时新建Node对象。
  • Vector:为List的古老实现类,与ArrayList几乎相同,线程安全,效率低,已弃用。

4.2 List接口中的常用方法(比Collection接口新增)

  • void add(int index, Object e):在index位置插入元素e
  • boolean addAll(int index, Collection c):从index位置开始将集合c中所有元素添加进来
  • Object get(int index):获取index位置的元素
  • int indexOf(Object e):返回元素e在集合中首次出现的位置
  • int lastIndexOf(Object e):返回元素e在集合中最后出现的位置
  • Object remove(int index):移除index位置的元素,并返回该元素(与Collection中的remove方法构成重载)
  • Object set(int index, Object e):设置index位置的元素为e
  • List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置左闭右开的子集合

5. Collection子接口二:Set

Set接口没有提供额外的方法,Set集合不允许包含相同的元素,判断两个对象是否相同根据equals()方法。Set的无序性不等于随机性,遍历的时候也会按特定顺序。HashSet底层也是用数组存储数据,存储数据时并非按数组索引的顺序添加,而是根据数据的Hash值决定的。

5.1 HashSet

  • HashSet是Set接口的典型实现,按Hash算法来存储集合中的元素,有很好的存取、查找、删除性能。
  • HashSet的特点有:① 不能保证元素的排列顺序;② 线程不安全;③ 集合元素可以是null
  • HashSet判断两个元素相等的标准:两个对象通过hashCode()方法比较相等,且两个对象的equals()方法返回值也相等。
  • 存放在HashSet容器中的对象,对应的类一定要重写equals()和hashCode(Object e)方法,且这两个方法尽可能保持一致性。
  • HashSet底层有数组+链表的结构。向HashSet中添加元素a时,首先调用a所在类的hashCode()方法,计算a的哈希值,此哈希值通过某种算法计算出在HashSet底层数组中的存放位置,判断该位置上是否已有元素。
  • 若没有其他元素,则a添加成功;
  • 若有其他元素b(或有以链表存储的多个元素b、c、…),则比较a与b的哈希值,若哈希值不相同,则a添加到该位置的链表末尾;
  • 若哈希值不同,则调用a所在类的equals()方法,若返回true,则a添加失败;
  • 若返回false,则a添加到该位置的链表末尾
    在这里插入图片描述

5.2 LinkedHashSet

  • LinkedHashSet是HashSet的子类,根据元素的hashCode值来决定元素的存储位置,同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的,遍历时按照添加的顺序遍历。
  • LinkedHashSet插入性能略低于HashSet,但在迭代访问元素时有很好的性能。

5.3 TreeSet

  • TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
  • TreeSet底层使用红黑树结构存储数据。
  • TreeSet有两种排序方法:自然排序(Comparable)&定制排序(Comparator)。默认情况下使用自然排序。

TreeSet set = new TreeSet(com);
空参构造器创建的对象为自然排序,带参构造器传入一个Comparator对象为定制排序

  • 向TreeSet中添加的数据,要求是相同类的对象,且该类的对象能够比较大小,不再用equals()方法比较是否相等,自然排序中使用compareTo()方法比较大小,定制排序使用compare()方法比较大小。

6. Map接口

4.1 Map的主要实现类

  • HashMap:Map的主要实现类,线程不安全,效率高,可以存储null的key和value
  • Hashtable:Map的古老实现类,线程安全,效率低,不能存储null的key和value
  • LinkedHashMap:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。保证在遍历Map元素时,可以按添加的顺序实现遍历
  • TreeMap:可以按照添加的key进行排序,实现排序遍历。底层使用红黑树
  • Properties:常用来处理配置文件。key和value都是String类型

4.2 Map的key-value结构

  • Map中的key:无序的、不可重复的,使用Set存储所有的key。要求key所在的类重写equals()和hashCode()方法(TreeMap要实现Comparable接口)
  • Map中的value:无序的、可重复的,使用Collection存储所有的value。要求value所在的类重写equals()方法
  • 一个key-value对构成了一个Entry对象,Map中的entry:无序的、不可重复的,使用Set存储所有的entry

4.3 HashMap的底层实现原理

  • jdk7中HashMap底层使用数组+链表结构存储,jdk8中HashMap底层使用数组+链表+红黑树结构存储
  • 在实例化后,jdk7底层创建了长度为16的一维Entry数组,默认临界因子0.75,
  • 向HashMap中添加元素key0-value0时,计算key0的哈希值,得到在Entry数组中的存放位置
  • 如果Entry数组存放位置上的数据为空,则key0-value0添加成功
  • 如果Entry数组存放位置上的数据不为空,则比较key0与已存在数据key的哈希值,若都不相同,则key0-value0添加成功
  • 若key0与某个数据key1的哈希值相同,继续比较key0与key1的equals()方法,若返回false,则key0-value0添加成功,以链表的方式存储;若返回true,则使用value0替换value1
  • 在添加数据过程中,当min(Entry数组长度 - 1, 临界因子*Entry数组长度)<=数组中元素个数,且数组Entry当前位置存在元素时,若需要Entry数组扩容,则将长度扩展为之前的2倍,并将原有数据复制过来
  • jdk8中实例化时并不创建数组,首次添加数据时才创建长度为16的Node数组,当数组某一个索引位置上的元素以链表形式存储的数据个数大于8,且当前Node数组长度大于64(否则扩容Node数组),则此时该索引位置上的所有数据改用红黑树存储

4.4 Map中的常用方法

  • Object put(Object key, Object value):添加,返回被覆盖的value
  • void putAll(Map m):全部添加
  • Object remove(Object key):移除指定的键值对,返回value
  • void clear():清空当前map中的所有数据
  • Object get(Object key):获取指定key对应的value
  • boolean containsKey(Object key):是否包含指定的key
  • boolean containsValue(Object value):是否包含指定的value
  • int size():返回map中键值对的个数
  • boolean isEmpty():判断当前map是否为空
  • boolean equals(Object e):判断当前map与e是否相等
  • Set keySet():返回所有key构成的Set集合,用于遍历所有的key
  • Collection values():返回所有value构成的Collection集合,用于遍历所有的value
  • Set entrySet():返回所有键值对构成的Set集合,用于遍历所有的键值对
Set entrySet = map.entrySet();
Iterator iterator = entrySet.iterator();
while(iterator.hasNext()){
    
    
	Object e = iterator.next();
	Map.Entry entry = (Map.Entry) e;
	System.out.println(entry.getKey() + ":" + entry.getValue());
}

4.5 Properties
存取数据时,建议使用setProperty(String key, String value)方法和getProperty(String key)方法

Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
properties.load(fileInputStream);
String name = properties.getProperty("name");
String password = properties.getProperty("password");
System.out.println(name + ":" + password);

7. Collections工具类

Collections是一个操作Collection、Map的工具类,提供了一系列静态的方法对集合元素进行排序、查询、修改等操作,还提供了对集合对象设置不可变,对集合对象实现同步控制等方法。

7.1 排序操作(均为static方法)

  • reverse(List):反转List中元素的顺序
  • shuffle(List):对List集合元素进行随机排序
  • sort(List):根据元素的自然顺序对指定List集合元素按升序排序
  • sort(List, Comparator):根据Comparator指定的顺序对List元素排序
  • swap(List, int, int):将LIst中的i处元素和j处元素进行交换

7.2 查找、替换

  • Object max(Collection)
  • Object max(Collection, Comparator)
  • Object min(Collection)
  • Object min(Collection, Comparator)
  • int frequency(Collection, Object):返回指定集合中指定元素的出现次数
  • void copy(List dest, LIst src):将src中的内容复制到dest中,要求dest中现有元素个数不少于src中的元素个数
  • boolean replaceAll(LIst list, Object oldVal, Object newVal):使用新值替换List对象的所有旧值

7.3 同步控制
Collections类中提供了多个synchronizedXxx()方法,该方法可将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题。

猜你喜欢

转载自blog.csdn.net/qq_43221336/article/details/108739756