javajavase

集合框架概述

一方面面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储
另一方面使用Array存储对象具有一些弊端,而Java集合就像一种容器,可以动态地把多个对象的引用放入容器中
集合、数组都是对多个数据进行存储操作的结构,简称Java容器

说明:此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt,.jpg,.avi,数据库中)

数组存储的特点

  • 数组初始化以后,长度就确定了
  • 数组声明的类型,就决定了进行元素初始化时的类型

比如:String[] arr; int[] arr1; Object[] arr2;
数组存储的弊端

  • 一旦初始化以后长度就不可变了,不便于扩展
  • 数组中提供的属性和方法少,不便于进行添加、删除、插入等操作,且效率不高
  • 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用
  • 数组存储数据的特点:有序、可重复。对于无序、不可重复的需求,不能满足

Java集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组
集合的使用场景
屏幕快照 2020-05-18 下午5.03.57.png
集合的分类
Java集合可分为Collection和Map两种体系

  • Collection接口:单列数据,定义了存取一组对象的方法的集合
    • List:元素有序、可重复的集合
    • Set:元素无序、不可重复的集合
  • Map接口:双列数据,保存具有映射关系“key-value对”的集合

集合框架结构
8C5737DA-3F13-47F6-BAC7-0D5C77AA0084.pngimage.png

  1. Collection接口:单列集合,用来存储一个一个的对象
  2. |----List接口:存储有序的、可重复的数据 -->“动态”数组
  3. |----ArrayList:线程不安全的,查询效率高,底层采用Object[] elementData数组存储
  4. |----LinkedList:对于频繁的插入删除操作,使用此类效率比ArrayList效率高底层采用双向链表存储
  5. |----Vector:作为List的古老实现类,线程安全的,效率低,底层采用Object[]数组存储
  6. |----Set接口:存储无序的、不可重复的数据 -->数学概念上的“集合”
  7. |----HashSet:作为Set接口主要实现类,线程不安全,可以存null
  8. |----LinkedHashSetHashSet的子类,遍历内部数据时,按照添加顺序遍历
  9. 遍历操作LinkedHashSet效率高于HashSet
  10. |----TreeSet:可以按照添加对象的指定属性,进行排序
  11. Map:双列数据,存储key-value对的数据 ---类似于高中的函数:y = f(x)
  12. |----HashMap:作为Map的主要实现类;线程不安全的,效率高;存储nullkeyvalue
  13. |----LinkedHashMap:保证在遍历map元素时,可以照添加的顺序实现遍历。
  14. 原因:在原的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。
  15. 对于频繁的遍历操作,此类执行效率高于HashMap
  16. |----TreeMap:保证照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序
  17. 底层使用红黑树
  18. |----Hashtable:作为古老的实现类;线程安全的,效率低;不能存储nullkeyvalue
  19. |----Properties:常用来处理配置文件。keyvalue都是String类型

Collection接口

屏幕快照 2020-05-18 下午5.16.03.png
Collection接口是ListSetQueue接口的父接口,该接口里定义的方法既可用于操作Set集合,也可用于操作List和 Queue集合

  • JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如Set和List)实现
  • 在Java5之前,集合会丢失容器中所有对象的数据类型,把所有对象都当成Object类型处理
  • 从Java5之后,增加了泛型以后,Java集合可以记住容器中对象的数据类型

    常用方法

    获取元素个数
    **int size()**获取元素个数
    添加
    **boolean add(Object obj)**
    **boolean addAll(Collection c)**
    删除
    **void clear()**清空集合
    **boolean remove(Object o)**会通过equals方法判断是否是要删除的元素,只会删除找到的第一个元素
    **boolean removeAll(Collection c)**删除两容器都包含的元素
    判断
    **boolean isEmpty()**
    **boolean contains(Object o)**会通过元素的equals方法来判断是否是同一个对象
    **boolean containsAll(Collection c)**判断是否都包含c中元素
    交集
    **boolean retainAll(Collection c)**把交集的结果存在当前的集合中,不影响c
    集合是否相等
    **boolean equals(Object obj)**比较俩集合是否相同
    转换成对象数组
    **Object [] toArray()**反过来是**Arrays.asList(T... a)**
    **Object [] toArray(T[] a)**
    获取集合对象的哈希值
    **hashCode()**
    遍历
    **Iterator<E> iterator()**返回迭代器对象,用于集合遍历 ```java @Test public void test(){ Collection coll = new ArrayList();

    // add(Object e):将元素e添加到集合coll中 coll.add(“AA”); coll.add(“BB”); coll.add(123);//自动装箱 coll.add(new Date());

    // size():获取添加的元素的个数 System.out.println(coll.size()); // 4

    // addAll(Collection coll1):将coll1集合中的元素添加到当前的集合中 Collection coll1 = new ArrayList(); coll1.add(456); coll1.add(“CC”);

    coll.addAll(coll1); System.out.println(coll.size()); // 6 System.out.println(coll);

    // clear():清空集合元素 coll.clear();

    // isEmpty():判断当前集合是否为空 System.out.println(coll.isEmpty()); }

@Test public void test1(){ Collection coll = new ArrayList(); coll.add(123); coll.add(456); coll.add(new Person(“Jerry”, 20)); coll.add(new String(“Tom”)); coll.add(false);

  1. // 1.contains(Object obj):判断当前集合中是否包含obj
  2. // 我们在判断时会调用obj对象所在类的equals()
  3. boolean contains = coll.contains(123);
  4. System.out.println(contains);
  5. System.out.println(coll.contains(new Person("Jerry",20))); // true
  6. // 2.containsAll(Collection coll1):判断形参coll1中的所有元素是否都存在于当前集合中。
  7. Collection coll1 = Arrays.asList(123,4567);
  8. System.out.println(coll.containsAll(coll1));

}

@Test public void test2(){ Collection coll = new ArrayList(); coll.add(123); coll.add(456); coll.add(new Person(“Jerry”,20)); coll.add(new String(“Tom”)); coll.add(false);

  1. // 3.remove(Object obj):从当前集合中移除obj元素
  2. coll.remove(1234);
  3. System.out.println(coll);
  4. coll.remove(new Person("Jerry",20));
  5. System.out.println(coll);
  6. // 4. removeAll(Collection coll1):差集:从当前集合中移除coll1中所有的元素。
  7. Collection coll1 = Arrays.asList(123,456);
  8. coll.removeAll(coll1);
  9. System.out.println(coll);

}

@Test public void test3(){ Collection coll = new ArrayList(); coll.add(123); coll.add(456); coll.add(new Person(“Jerry”,20)); coll.add(new String(“Tom”)); coll.add(false);

  1. // 5.retainAll(Collection coll1):交集:获取当前集合和coll1集合的交集,并返回给当前集合
  2. Collection coll1 = Arrays.asList(123,456,789);
  3. coll.retainAll(coll1);
  4. System.out.println(coll);
  5. // 6.equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同。
  6. Collection coll1 = new ArrayList();
  7. coll1.add(456);
  8. coll1.add(123);
  9. coll1.add(new Person("Jerry",20));
  10. coll1.add(new String("Tom"));
  11. coll1.add(false);
  12. System.out.println(coll.equals(coll1));
  13. // 7.hashCode():返回当前对象的哈希值
  14. System.out.println(coll.hashCode());

}

  1. **集合与数组间的转换**
  2. ```java
  3. // 8.集合 --->数组:toArray()
  4. Object[] arr = coll.toArray();
  5. for(int i = 0; i < arr.length; i++) {
  6. System.out.println(arr[i]);
  7. }
  8. // 拓展:数组 --->集合:调用Arrays类的静态方法asList(T... a)
  9. List<String> list = Arrays.asList(new String[]{"AA", "BB", "CC"});
  10. System.out.println(list);
  11. List arr1 = Arrays.asList(new int[]{123, 456});
  12. System.out.println(arr1.size()); //1 🔴基本类型数组被当成了一个元素
  13. List arr2 = Arrays.asList(new Integer[]{123, 456});
  14. System.out.println(arr2.size()); //2 引用类型数组不会
  15. //Arrays中asList方法
  16. public static <T> List<T> asList(T... a) {
  17. return new ArrayList<>(a); // 这个ArrayList是Arrays的私有静态内部类
  18. }
  19. // 9.iterator():返回Iterator接口的实例,用于遍历集合元素。放在IteratorTest.java中测试

说明:向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()
补充

  1. @Test
  2. public void test1(){
  3. Collection coll = new ArrayList();
  4. coll.add(123);
  5. coll.add(456);
  6. coll.add(343);
  7. coll.add(343);
  8. coll.forEach(System.out::println); // Iterable接口的default方法,用于遍历
  9. }
  10. default void forEach(Consumer<? super T> action) {
  11. Objects.requireNonNull(action);
  12. for (T t : this) {
  13. action.accept(t);
  14. }
  15. }

Iterator与foreach
遍历Collection的两种方式

  • 使用迭代器Iterator
  • foreach循环(或增强for循环)

    迭代器接口Iterator

    java.utils.Iterator

    Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素 GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。迭代器模式,就是为容器而生。类似于“公交车上的售票员”、“火车上的乘务员”、“空姐”

概述、Collection、Iterator、foreach - 图5
创建

  • Collection接口继承了java.lang.Iterable接口
  • Iterable接口有一个iterator()方法,用以返回一个实现了Iterator接口的对象
  • 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前

作用

  • Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力

如果需要创建Iterator对象,则必须有一个被迭代的集合

  • 在调用**next()**方法之前必须要调用**hasNext()**进行检测

若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常

  1. @Test
  2. public void test1(){
  3. Collection coll = new ArrayList();
  4. coll.add(123);
  5. coll.add(456);
  6. coll.add(new Person("Jerry",20));
  7. coll.add(new String("Tom"));
  8. coll.add(false);
  9. Iterator iterator = coll.iterator();
  10. // 方式一:
  11. // System.out.println(iterator.next());
  12. // System.out.println(iterator.next());
  13. // System.out.println(iterator.next());
  14. // System.out.println(iterator.next());
  15. // System.out.println(iterator.next());
  16. // //报异常:NoSuchElementException
  17. // System.out.println(iterator.next());
  18. // 方式二:不推荐
  19. // for(int i = 0; i < coll.size(); i++) {
  20. // System.out.println(iterator.next());
  21. // }
  22. // 方式三:推荐
  23. // hasNext():判断是否还有下一个元素
  24. while(iterator.hasNext()) {
  25. //next():①指针下移 ②将下移以后集合位置上的元素返回
  26. System.out.println(iterator.next());
  27. }
  28. }
  29. @Test
  30. public void test2(){
  31. Collection coll = new ArrayList();
  32. coll.add(123);
  33. coll.add(456);
  34. coll.add(new Person("Jerry",20));
  35. coll.add(new String("Tom"));
  36. coll.add(false);
  37. //错误方式一:❌
  38. // Iterator iterator = coll.iterator();
  39. // while((iterator.next()) != null){
  40. // System.out.println(iterator.next());
  41. // }
  42. //错误方式二:❌
  43. //集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
  44. while (coll.iterator().hasNext()){
  45. System.out.println(coll.iterator().next());
  46. }
  47. }

iterator中的remove()方法

  • 内部定义了remove(),可以在遍历的时候删除集合中的元素。此方法不同于集合直接调用remove()
  • 未调用next()直接remove()或连续两次调用remove()都会报IllegalStateException

    1. @Test
    2. public void test3(){
    3. Collection coll = new ArrayList();
    4. coll.add(123);
    5. coll.add(456);
    6. coll.add(new Person("Jerry",20));
    7. coll.add(new String("Tom"));
    8. coll.add(false);
    9. //删除集合中"Tom"
    10. Iterator iterator = coll.iterator();
    11. while (iterator.hasNext()) {
    12. // iterator.remove();
    13. Object obj = iterator.next();
    14. if("Tom".equals(obj)){
    15. iterator.remove();
    16. }
    17. }
    18. //遍历集合
    19. iterator = coll.iterator();
    20. while (iterator.hasNext()){
    21. System.out.println(iterator.next());
    22. }
    23. }

    foreach——JDK5新特性

    Java5提供了foreach循环迭代访问集合和数组

  • 遍历操作不需获取Collection或数组的长度,无需使用索引访问元素

  • foreach的底层调用Iterator完成操作 ```java @Test public void test1() { Collection coll = new ArrayList(); coll.add(123); coll.add(456); coll.add(new Person(“Jerry”,20)); coll.add(new String(“Tom”)); coll.add(false);

    // for(集合元素的类型 局部变量 : 集合对象) // 内部仍然调用了迭代器。 for(Object obj : coll) {

    1. System.out.println(obj);

    } }

// 遍历数组 @Test public void test2() { int[] arr = new int[]{1,2,3,4,5,6}; // for(数组元素的类型 局部变量 : 数组对象) for(int i : arr) { System.out.println(i); } }

  1. **练习**
  2. ```java
  3. @Test
  4. public void test3(){
  5. String[] arr = new String[]{"MM","MM","MM"};
  6. // 方式一:普通for赋值 会改
  7. for (int i = 0; i < arr.length; i++) {
  8. arr[i] = "GG";
  9. }
  10. // 方式二:增强for循环不改原值
  11. for(String s : arr){
  12. s = "GG";
  13. }
  14. for(int i = 0; i < arr.length; i++){
  15. System.out.println(arr[i]);
  16. }
  17. }