曹阳的博客 仅用于学习和分享

Java集合

2019-10-30

核心类库D3:集合框架、Collection集合、List集合、泛型机制、Queue集合、Set集合、Map集合

Collection.png

1.集合框架

1.1 复习

  1. 当需要在程序中记录单个数据内容时,则声明一个变量记录即可;
  2. 当需要在程序中记录多个类型相同的数据内容时,则声明一个一维数组记录即可;
  3. 当需要在程序中记录多个类型不同的数据内容时,则构造一个对象记录即可;
  4. 当需要在程序中记录多个类型相同的对象时,则声明一个对象数组记录即可;
  5. 当需要在程序中记录多个类型不同的对象时,则声明一个集合记录即可;

1.2 框架结构

  1. 在Java语言中用于描述集合的顶层框架:Collection集合 和 Map集合。
  2. 其中Collection集合中存取元素的基本单位是:单个元素。
  3. 其中Map集合中存取元素的基本单位是:单对元素。
  4. 在以后的开发中很少直接使用Collection集合,而是更多地使用Collection集合的子集合:List集合、Queue集合以及Set集合。

2.Collection集合(java.util包)

2.1 常用的方法(练熟、记住)

  1. boolean add(E e):向集合里添加对象,成功返回true,失败返回false
    当打印集合中的所有元素时,本质上就是调用各个元素对应类中的toString
  2. bollean contains(Object obj):查找集合中有没有参数传入的对象,有则返回true,没有则返回false
    • contains方法的工作原理是o==null ? e==null : o.equals(e)
    • 若参数对象为空,则只需要查找当前集合中是否有元素为null
    • 若参数对象不为空,则使用参数对象调用equals方法与集合中元素依次比较
    • 当Student类中没有重写equals方法时,调用继承的版本,比较地址,返回false
    • 当Student类中重写equals方法后,调用重写的版本,比较内容,返回true
    • Java官方写好的类Java官方已经重写了equals,所以比较的是内容,而我们自己写的类必须重写equals才能比较内容
  3. bollean remove(Object obj):删除成功返回true,失败返回false
  4. void clear():全删,清空
  5. int size():返回集合中元素的个数
    没有声明,直接用的变量肯定是成员变量

3.List集合(重中之重)

3.1 基本概念

  1. java.util.List集合是Collection集合的子集合,元素有先后放入次序并且可以重复
  2. 该集合的主要实现类有:ArrayList类、LinkedList类、Stack类以及Vector类。
  3. 其中ArrayList类的底层是采用数组进行数据管理的,访问方便但增删不方便。
  4. 其中LinkedList类的底层是采用链表进行数据管理的,增删方便但访问不方便。
  5. 其中Stack类的底层是采用数组进行数据管理的,该类主要用于描述具有后进先出特性的数据结构,叫做栈(last in first out 简称为:LIFO)。
  6. 其中Vector类的底层是采用数组进行数据管理的,与ArrayList类相比属于早期提供的类,支持线程安全,但效率比较低,以后的开发中首选ArrayList类。

3.2 常用的方法

  1. void add(int index,E element):向集合中指定位置添加元素
    • 有new的是放到堆区里,没有new的是放到常量池里
    • 集合里之所以能放各种类型的对象,是因为这些对象都被看做Object类型放入的,取出来的类型也是Object类型
  2. boolean addAll(int index,Collection<?extends E>c):向集合中添加所有元素
  3. E get(int index):从集合中获取指定位置元素
    • 你的数据类型是什么类型就要强转成什么类型,否则就会出现类型转换异常
  4. E set(int index,E element):修改指定位置的元素,返回被修改的元素
  5. E remove(int index):删除指定位置的元素,返回被删除的元素
  6. subList(1,list):获取List子集合,子集和原List共用一个地址

4.泛型机制(重点)

4.1 基本概念

  1. 通常情况下集合中可以存放不同类型的对象,是因为集合将这些对象全部看做Object类型放入的,当从集合中取出元素时也是Object类型的,为了表达该元素最真实的数据类型则需要进行强制类型转换,此时可能引发类型转换异常。
  2. 为了避免上述错误的发生,从jdk1.5开始提出泛型机制,也就是在集合名称的右侧使用<数据类型>的方式明确要求该集合中可以存放元素的类型,若放入其他类型的元素则编译报错,如: `List lt1 = new LinkedList();`
  3. 使用泛型机制就不用强转了
  4. 菱形特性:后面那个里什么都没有`<>`,jdk1.7开始
  5. 类名或接口名后面带<E>的表示支持泛型

4.2 泛型的本质

  1. 泛型的本质就是参数化类型,也就是让数据类型作为参数传递
  2. 其中集合中E作为形参负责占位,当使用集合时<>中的数据类型作为实参给E进行赋值操作,从而使得集合中所有的E都被替换为实参指定的类型。
  3. 由于实参的传递支持各种各样广泛的类型,因此得名为”泛型机制”
    // 其中i表示形式参数,负责占位            其中E表示形式参数,负责占位  
    // int i = 2;                             E = String;  
    // int i = 5;                             E = Student;  
    public void show(int i) {                 public class List<E> {  
      ...                                        ...  
    }                                         }  
    // 其中2表示实际参数,用于给形参初始化    // 其中String表示实际参数  
    show(2);                                  List<String> lt1 = ...;  
    show(5);                                  List<Student> lt2 = ...;  
    

5.Queue集合(重点)

5.1 基本概念

  1. java.util.Queue集合是Collection集合的子集合,与List集合属于平级关系。
  2. 该集合主要用于描述具有先进先出特征的数据结构,叫做队列(first in first out,FIFO)。
  3. 该集合的主要实现类有:LinkedList类,该类在增删方面有优势。

5.2 常用的方法

  1. boolean offer(E e):将一个对象添加至队尾,若添加成功则返回true
  2. E poll():从队首删除并返回一个元素
  3. E peek():返回队首的元素(但并不删除)

5.3 练习:

准备一个Queue集合,将数据11、22、33、44、55进行依次入队操作并打印,然后查看队首元素值并打印出来,再将队列中的所有元素依次出队并打印,最后打印队列中最终的所有元素。

6.Set集合(重点)

6.1 基本概念

  1. java.util.Set集合是Collection集合的子集合,与List集合以及Queue集合属于平级
  2. 该集合与List集合相比元素没有先后放入次序,并且不允许有重复的元素。
  3. 该集合的主要实现类有:HashSet类 和 TreeSet类。
  4. 其中HashSet类的底层是采用哈希表进行数据管理的。
  5. 其中TreeSet类的底层是采用二叉树进行数据管理的。

6.2 常用的方法

  1. 参考Collection集合中的方法即可;
  2. Iterator iterator() - 用于获取当前集合中的迭代器对象,可以取出每个元素。
  3. 其中Iterator是个接口类型,该接口的常用方法有:
    • boolean hasNext() - 用于判断集合中是否有可以访问的元素。
    • E next() - 用于获取集合中一个元素并指向下一个元素。
    • void remove() - 用于删除迭代器获取到的元素。
  4. 注意:当使用迭代器迭代集合中的所有元素时,若使用集合中的remove方法来删除元素,则会出现ConcurrentModificationException并发修改异常,以后的开发中应该使用迭代器的remove方法来删除元素。
  5. 思考:为啥要保证hashCode方法和equals方法的一致性???
    解析:只要equals方法相等则要求hashCode相同,而哈希码值相同时使用同一个哈希算法算出来的索引位置就相同,从而避免同一个元素所在索引位置不同引发的错误。

6.3 使用迭代器来访问集合中的所有元素[one, two]

  1. 调用成员方法获取迭代器对象
    Iterator<String> it = s1.iterator();
  2. 使用迭代器对象获取每个元素并打印
    //判断该迭代器指向的集合中是否拥有可以迭代/遍历的元素  
    System.out.println(it.hasNext()); // true  
    //获取一个元素并指向下一个位置  
    //与toString方法相比取出的是单个元素,更加灵活  
    System.out.println("获取到的元素是:" + it.next()); //one   
    while(it.hasNext()) {  
     System.out.println("获取到的元素是:" + it.next());  
    }  
    

6.4 增强版的for循环遍历(for each结构)

  1. 语法格式
    for(元素类型 变量名 : 数组/集合的名称) {  
      循环体;  
    }  
    
  2. 执行流程
    不断地从数组或集合中取出一个元素赋值给变量后执行循环体,直到所有元素取完为止

  3. 总结:
    • 遍历Set集合中所有元素的方式有3种:toString方法、for each结构、迭代器
    • 遍历List集合中所有元素的方式有4种:除了上述3种外还有get方法。

7.Map集合(重点)

7.1 基本概念

  1. java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,具体类型参数如下:
    K - 此映射所维护的键(Key)的类型
    V - 映射值(Value)的类型
  2. 该集合中不能包含重复的键;每个键最多只能映射到一个值。
  3. 该集合的主要实现类有:HashMap类 和 TreeMap类。
  4. 其中HashMap类的底层是采用哈希表进行数据管理的。
  5. 其中TreeMap类的底层是采用二叉树进行数据管理的。

7.2 常用的方法

  1. V put(K key,V value);将key-value对存入Map,若集合中已经包含该key,则替换该Key所对应的Value,返回值为该Key原来所对应的Value,若没有则返回null(增加和修改)
  2. V get(Object key);返回与参数Key所对应的Value对象,如果不存在则返回null(修改)
  3. boolean containsKey(K Key);查找键是否存在,存在即返回true,不存在即返回false
  4. boolean containsValue(V Value);查找数据是否存在,存在即返回true,不存在即返回false
  5. V remove(K Key);删除元素,不存在该元素则返回null,存在该元素则返回该元素本身

7.3 遍历Map集合

  1. 方式1:toString方法
  2. 方式2:enTrySet方法,以键值对为基本单位进行转换
    Set<Map.Entry<Integer,String>> s1 = m1.entrySet();  
    for(Map.Entry<Integer,String> me : s1) {  
     System.out.println(me);  
     me.getKey();  
     me.getValue();  
    }  
    
  3. 方式3:keySet方法,以键为基本单位进行转换(常用)
    Set<Integer> s2 = m1.keySet();  
    for(Integer it : s2){  
     System.out.println(it+"="+m1.get(in));  
    }  
    

7.4 Map集合的实际应用

  1. Map集合是面向对象查询优化的数据结构,在大数据量情况下有着优良的查询性能,经常用于根据key检索value的业务场景
  2. 用户登陆数据缓冲:用户名是key,用户对象是value,在登录验证的时候根据用户名快速查询用户信息
  3. 登录会话保持状态:在网站编程中,用户会话状态保持经常采用Map存储,可以快速在数以万计的信息中快速确定用户是否已经登录

注意

  1. 一维数组的容量就是初始容量16
  2. 加载因子75%,16*75%=12,就是索引下标位置里面,当有12个下标位置已经挂满了元素时,可以认为这个数组即将挂满,底层就会自动扩容

对比数组

  数组 集合
是否连续 连续 不连续
数据内容类型是否相同 类型相同 可以不同
是否支持下标访问 支持 部分支持
增删是否 移动大量元素 可能会移动 可以不移动
长度大小是否可变 不可 可以
数据内容类型 基本和引用 引用(基本类型可通过包装类转换)

作业:

  1. 复习和练习List集合的常用方法并进行整理。
  2. 查询java.util.Stack类,实现将11 22 33 44 55依次入栈再出栈。
    • push():入栈
    • peek():查栈顶元素
    • pop():出栈
  3. 提示用户按照指定的格式输入生日信息,计算距离1970年1月1日的天数并打印出来
  4. 复习和总结集合的所有内容,重点掌握Queue集合和Stack集合的代码。
  5. 准备一个HashSet集合,实现生成10个1~20之间不重复的随机数放入集合并打印。
    集合中只能放引用类型数据
  6. 声明一个List集合放入11、22、33、44、55,分别使用4种方式遍历。
  7. 准备一个HashMap集合,统计字符串”123,456,789,123,456”中每个数字字符串出现的次数并打印出来。

上一篇 Java核心类库2

下一篇 Java异常机制

Content