集合的概述

  • 当需要在Java程序中记录单个数据内容时,则声明一个变量。
  • 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组。
  • 当需要在Java程序中记录多个类型不同的数据内容时,则创建一个对象。
  • 当需要在Java程序中记录多个类型相同的对象数据时,创建一个对象数组。
  • 当需要在Java程序中记录多个类型不同的对象数据时,则准备一个集合。
  • Java中集合框架顶层框架是:java.util.Collection集合 和 java.util.Map集合。
  • 其中Collection集合中存取元素的基本单位是:单个元素。
  • 其中Map集合中存取元素的基本单位是:单对元素。

集合类库 - 图1

Collection集合(重点!!)

java.util.Collection接口是List接口、Queue 接口以及Set接口的父接口,因此该接口里定义的方法既可用于操作List集合,也可用于操作Queue集合和Set集合。


boolean add(E e);

向集合中添加对象

boolean addAll(Collection<? extends E>
c)

用于将参数指定集合c中的所有元素添加到当前集合中

boolean contains(Object o);

判断是否包含指定对象

boolean containsAll(Collection<?> c)

判断是否包含参数指定的所有对象

boolean retainAll(Collection<?> c)

保留当前集合中存在且参数集合中存在的所有对象

boolean remove(Object o);

从集合中删除对象

boolean removeAll(Collection<?> c)

从集合中删除参数指定的所有对象


void clear(); 清空集合
int size(); 返回包含对象的个数
boolean isEmpty(); 判断是否为空
boolean equals(Object o) 判断是否相等
int hashCode() 获取当前集合的哈希码值
Object[] toArray() 将集合转换为数组
Iterator iterator() 获取当前集合的迭代器
  1. package com.lagou.task14;
  2. import java.util.ArrayList;
  3. import java.util.Arrays;
  4. import java.util.Collection;
  5. import java.util.List;
  6. /**
  7. * @author lijing
  8. * @date 2020/10/9 10:50
  9. * @description
  10. */
  11. public class CollectionTest {
  12. @Override
  13. public boolean equals(Object obj) {
  14. return super.equals(obj);
  15. }
  16. public static void main(String[] args) {
  17. //1.准备一个Collection集合并打印
  18. //Collection c1 =new Collection();//接口不能实例化 也就是不能创建对象
  19. //接口类型的引用指向实现类的对象,形成了多态
  20. Collection c1=new ArrayList();
  21. //自动调用toString方法,调用ArrayList中的toString方法,默认打印格式为:[元素1,元素2,...]
  22. System.out.println(c1);
  23. System.out.println("-----------------");
  24. //2.向集合中添加单个元素并打印
  25. c1.add(new String("abc"));
  26. c1.add(Integer.valueOf(2));
  27. c1.add(new Person("张飞",30));
  28. //打印集合中的所有元素时,本质上就是打印集合中的每个对象,也就是每个对象调用对应类的toString方法
  29. System.out.println(c1);
  30. System.out.println("----------------------");
  31. //3.向集合总添加多个元素并打印
  32. Collection c2=new ArrayList();
  33. c2.add("three");//常量池
  34. c2.add(4); //自动装箱机制
  35. System.out.println("c2="+c2);
  36. //将c2中的所有元素全部添加到集合c1当中
  37. c1.addAll(c2);
  38. //表示将集合c2整体看做一个元素添加到集合c1当中
  39. //c1.add(c2)
  40. System.out.println("c1="+c1);
  41. System.out.println("--------------------------------");
  42. //4.判断集合中是否包含参数指定的单个元素
  43. boolean b1 = c1.contains(new String("one"));
  44. System.out.println("b1="+b1);//false
  45. b1 = c1.contains(new String("abc"));
  46. System.out.println("b1="+b1);//true
  47. b1 = c1.contains(Integer.valueOf(2));
  48. System.out.println("b1="+b1);//true
  49. b1 = c1.contains(Integer.valueOf(3));
  50. System.out.println("b1="+b1);//false
  51. //contains方法的工作原理是:Object.equals(o,e),而该方法的equals的工作原理是:
  52. //当Person类中没有重写equals方法时,则调用从Object类中继承下来的equals方法,比较两个对象的地址
  53. //当Person类中重写equals方法后,则调用重写以后的版本,比较两个对象的内容 true
  54. b1 = c1.contains(new Person("张飞",30));
  55. System.out.println("b1="+b1);//false true
  56. System.out.println("-----------------------------------");
  57. System.out.println("c1="+c1);
  58. //c1=[abc, 2, Person{name='张飞', age=30}, three, 4]
  59. //5.判断当前集合中是否包含参数指定集合的所有元素
  60. Collection c3=new ArrayList();
  61. c3.add(4);
  62. System.out.println("c3="+c3);//[4]
  63. //判断集合c1中是否包含集合c3中的所有元素
  64. b1=c1.containsAll(c3);
  65. System.out.println("b1="+b1);//true
  66. //只有集合c3中的所有元素都在集合c1中出现才会返回true,否则都是fasle
  67. c3.add("five");
  68. b1=c1.containsAll(c3);
  69. System.out.println("b1="+b1);//false
  70. System.out.println("----------------------------------------");
  71. //笔试考点
  72. System.out.println("c2="+c2);
  73. System.out.println("c1="+c1);
  74. b1=c1.containsAll(c2);
  75. System.out.println(b1);//true
  76. //判断集合c1中是否拥有集合c2这个整体为单位的元素
  77. b1=c1.contains(c2);
  78. System.out.println(b1);//false
  79. System.out.println("----------------------------------------");
  80. //6.计算两个集合的交集并保留到当前集合中
  81. System.out.println(c2);//[three,4]
  82. System.out.println(c3);//[4,five]
  83. //让集合自己和自己取交集
  84. b1=c2.retainAll(c2);
  85. System.out.println(b1);//false
  86. //计算集合c2和c3的交集并保留到集合c2中,取代集合c2中原有的数值
  87. b1 = c2.retainAll(c3);
  88. System.out.println(b1);//true
  89. System.out.println(c2);//[4]
  90. System.out.println(c3);//[4,five]
  91. System.out.println("----------------------------------------");
  92. //7.实现集合中单个元素和所有元素的删除操作
  93. //remove方法的工作原理是:Object.equals(o,e)
  94. System.out.println(c1);//[abc, 2, Person{name='张飞', age=30}, three, 4]
  95. //删除参数指定的单个元素
  96. b1=c1.remove(1);
  97. System.out.println(b1);//false
  98. b1=c1.remove("abc");
  99. System.out.println(b1);//true
  100. System.out.println(c1);//[2, Person{name='张飞', age=30}, three, 4]
  101. b1=c1.remove(new Person("张飞",30));
  102. System.out.println(c1);//[2, three, 4]
  103. //8.实现集合中所有元素的删除操作(交集),本质上就是一个一个元素进行删除,有元素就删除,没有不删除
  104. System.out.println(c3);//[4, five]
  105. //从集合c1中删除集合c3中的所有元素
  106. b1=c1.removeAll(c3);
  107. System.out.println(b1);
  108. System.out.println(c1);//[2, three]
  109. System.out.println(c3);//[4, five] c3不会发生改变
  110. //笔试考点 删除整体对象c3
  111. b1=c1.remove(c3);
  112. System.out.println("b1=" + b1);//false
  113. System.out.println("c1=" + c1);//c1=[2, three]
  114. System.out.println("----------------------------------------");
  115. //实现集合中其他方法的测试
  116. System.out.println("集合中元素的个数为:" + c1.size());
  117. System.out.println(0 == c1.size() ? "集合已经空了" : "集合还没有空");
  118. System.out.println(c1.isEmpty() ? "集合已经空了" : "集合还没有空");
  119. c1.clear();
  120. System.out.println("集合中元素的个数为:" + c1.size());
  121. System.out.println(0 == c1.size() ? "集合已经空了" : "集合还没有空");
  122. System.out.println(c1.isEmpty() ? "集合已经空了" : "集合还没有空");
  123. //准备两个集合并判断是否相等
  124. ArrayList c4 = new ArrayList();
  125. c4.add(1);
  126. c4.add(2);
  127. System.out.println(c4);
  128. ArrayList c5 = new ArrayList();
  129. c5.add(1);
  130. c5.add(2);
  131. System.out.println(c5);
  132. b1=c4.equals(c5);
  133. System.out.println(b1);//true
  134. System.out.println("----------------------------------------");
  135. //10.实现集合和数组类型之间的转换 通常认为集合是用于取代数组的结构
  136. Object[] objects = c5.toArray();
  137. //打印数组中的所有元素
  138. System.out.println(Arrays.toString(objects));
  139. //实现数组到集合类型的转换
  140. // List<Object> objects1 = Arrays.asList(objects);
  141. Collection objects1 = Arrays.asList(objects);
  142. System.out.println("集合中的元素有:" + objects1);
  143. }
  144. }

Iterator接口和foreach循环(重点)

Itertor:

  • java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。
  • java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都组和集合的遍历。
  • 是经典迭代的“简化版”。
    |
    boolean hasNext() |
    判断集合中是否有可以迭代/访问的元素 | | —- | —- | |
    E next() |
    用于取出一个元素并指向下一个元素 | |
    void remove() |
    用于删除访问到的最后一个元素 |
  1. package com.lagou.task14;
  2. import java.util.ArrayList;
  3. import java.util.Collection;
  4. import java.util.Iterator;
  5. /**
  6. * @author lijing
  7. * @date 2020/10/9 14:04
  8. * @description
  9. */
  10. public class CollectionPointTest {
  11. public static void main(String[] args) {
  12. //1.准备一个Collection集合并放入元素打印
  13. ArrayList c1 = new ArrayList();
  14. c1.add("one");
  15. c1.add(2);
  16. c1.add(new Person("张飞", 30));
  17. //遍历方式一:自动调用toString方法 String类型的整体
  18. System.out.println("c1=" + c1);//c1=[one, 2, Person{name='张飞', age=30}]
  19. //2.遍历方式二:使用迭代器来遍历集合
  20. //2.1获取当前集合中的迭代器对象
  21. Iterator iterator1 = c1.iterator();
  22. //2.2判断是否有元素可以访问
  23. while (iterator1.hasNext()) {
  24. //2.3去除一个元素并指向下一个元素
  25. System.out.println("获取到的元素是:" + iterator1.next());
  26. }
  27. //3.使用迭代器来模拟toString方法的打印效果
  28. //由于上个循环已经使用迭代器走到了租后,因此需要重置迭代器
  29. iterator1=c1.iterator();
  30. StringBuilder sb1=new StringBuilder();
  31. sb1.append("[");
  32. while(iterator1.hasNext()){
  33. // sb1.append(iterator1.next()).append(",").append(" ");
  34. Object next = iterator1.next();
  35. if (!iterator1.hasNext()){
  36. sb1.append(next).append("]");
  37. }else{
  38. sb1.append(next).append(",").append(" ");
  39. }
  40. }
  41. System.out.println(sb1);
  42. //4.不断地去获取集合中的元素并判断,当元素值为:"one"时删除该元素
  43. Collection c4=new ArrayList();
  44. c4.add("1");
  45. c4.add(2);
  46. c4.add(3);
  47. c4.add("1");
  48. c4.add(3);
  49. c4.add("1");
  50. c4.add(1);
  51. c4.add(1);
  52. c4.add(1);
  53. c4.add(1);
  54. // c4.remove(1);
  55. // c4.removeAll();
  56. System.out.println(c4);
  57. Iterator iterator = c4.iterator();
  58. while(iterator.hasNext()){
  59. Object next = iterator.next();
  60. if("1".equals(next)){
  61. iterator.remove();
  62. }
  63. }
  64. System.out.println(c4);
  65. System.out.println("--------");
  66. iterator = c4.iterator();
  67. while(iterator.hasNext()){
  68. Object next = iterator.next();
  69. if(Integer.valueOf(1).equals(next)){
  70. iterator.remove();
  71. }
  72. }
  73. System.out.println(c4);
  74. //5.使用for each循环实现集合和数组中元素的遍历,代码简单且方法灵活
  75. for (Object obj :c1) {
  76. System.out.println("取出的元素为:" + obj);
  77. }
  78. int[] arr=new int[]{22,33,44,55,66,77,88};
  79. for (int i :arr) {
  80. System.out.println(i);
  81. }
  82. }
  83. }

List集合(重中之重)

  • java.util.List集合是Collection集合的子集合,该集合中允许有重复的元素并且有先后放入次序。
  • 该集合的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类。
  • 其中ArrayList类的底层是采用动态数组进行数据管理的,支持下标访问,增删元素不方便。
  • 其中LinkedList类的底层是采用双向链表进行数据管理的,访问不方便,增删元素方便。
  • 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别,ArrayList更适合于机访问而LinkedList更适合于插入和删除;在性能要求不是特别苛刻的情形下可以忽略这个差别。
  • 其中Stack类的底层是采用动态数组进行数据管理的,该类主要用于描述一种具有后进先出特征的数据结构,叫做栈(last in first out LIFO)。
  • 其中Vector类的底层是采用动态数组进行数据管理的,该类与ArrayList类相比属于线程安全的类,效率比较低,以后开发中基本不用。 |
    void add(int index, E element) |
    向集合中指定位置添加元素 | | —- | —- | |
    boolean addAll(int index, Collection<? extends E> c) |
    向集合中添加所有元素 | |
    E get(int index) |
    从集合中获取指定位置元素 | |
    int indexOf(Object o) |
    查找参数指定的对象 | |
    int lastIndexOf(Object o) |
    反向查找参数指定的对象 | |
    E set(int index, E element) |
    修改指定位置的元素 | |
    E remove(int index) |
    删除指定位置的元素 | |
    List subList(int fromIndex, int toIndex) |
    用于获取子List |
  1. 准备一个Stack集合,将数据1122334455依次入栈并打印,然后查看栈顶元素并打印,
  2. 然后将栈中所有数据依次出栈并打印。
  3. 再准备一个Stack对象,将数据从第一个栈中取出来放入第二个栈中,然后再从第二个栈中取出并
  4. 打印。
  5. package com.lagou.task14;
  6. import java.util.Stack;
  7. /**
  8. * @author lijing
  9. * @date 2020/10/9 17:00
  10. * @description
  11. */
  12. public class StackTest {
  13. public static void main(String[] args) {
  14. //1.准备一个Stack类型的对象并打印
  15. Stack s1=new Stack();
  16. Stack s2=new Stack();
  17. System.out.println(s1);//[]
  18. System.out.println(s2);//[]
  19. //2.将11 22 33 44 55 一次入栈并打印
  20. // s1.push(11);
  21. // s1.push(22);
  22. // s1.push(33);
  23. // s1.push(44);
  24. // s1.push(55);
  25. for (int i = 1; i <6; i++) {
  26. Object obj = s1.push(i * 11);
  27. // System.out.println("入栈的元素是:"+obj);
  28. System.out.println("栈中的元素有:"+s1);
  29. }
  30. System.out.println(s1);
  31. //3.查看栈顶元素值并打印
  32. System.out.println("栈顶元素为:" + s1.peek());
  33. //4.对栈中所有元素一次出站并打印
  34. for (int i = 0; i < s1.size();) {
  35. Object to = s1.pop();
  36. System.out.println("出栈元素为:" + to);//55 44 33 22 11
  37. s2.push(to);
  38. }
  39. //5.最终打印栈中的所有元素
  40. System.out.println("s1="+s1);//[]
  41. for (int i = 0; i < s2.size();) {
  42. Object pop = s2.pop();
  43. System.out.println("出栈的元素为:" + pop);
  44. }
  45. }
  46. }

Queue集合(重点)

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

集合类库 - 图2


boolean offer(E e)

将一个对象添加至队尾,若添加成功则返回true

E poll()

从队首删除并返回一个元素

E peek()

返回队首的元素(但并不删除)
  1. 准备一个Queue集合,将数据1122334455依次入队并打印,然后查看队首元素并打印,
  2. 然后将队列中所有数据依次出队并打印。
  3. package com.lagou.task14;
  4. import java.util.LinkedList;
  5. import java.util.Queue;
  6. /**
  7. * @author lijing
  8. * @date 2020/10/9 17:12
  9. * @description
  10. */
  11. public class QueueTest {
  12. public static void main(String[] args) {
  13. //1.准备一个Queue集合并打印
  14. Queue queue=new LinkedList();
  15. //2.将数据11 22 33 44 55 一次入队并打印
  16. for (int i = 1; i <=5; i++) {
  17. queue.offer(i * 11);
  18. // System.out.println("入队的元素为为:");
  19. System.out.println("入队的集合为:"+queue);
  20. }
  21. //3.然后查看队首元素并打印
  22. System.out.println("队首元素为:"+queue.peek());
  23. //4.然后将队列中所有数据依次出队并打印
  24. for (int i=1;i<=queue.size();){
  25. Object poll = queue.poll();
  26. System.out.println("出队的元素为:"+poll);
  27. // System.out.println("出队后的集合为:"+queue);
  28. }
  29. //5.查看队列中最终的元素
  30. System.out.println(queue);
  31. }
  32. }

泛型机制(熟悉)

基本概念

  • 通常情况下集合中可以存放不同类型的对象,是因为将所有对象都看做Object类型放入的,因此从集合中取出元素时也是Object类型,为了表达该元素真实的数据类型,则需要强制类型转换,而强制类型转换可能会引发类型转换异常。
  • 为了避免上述错误的发生,从Java5开始增加泛型机制,也就是在集合名称的右侧使用<数据类型>的方式来明确要求该集合中可以存放的元素类型,若放入其它类型的元素则编译报错。
  • 泛型只在编译时期有效,在运行时期不区分是什么类型。

    底层原理

    泛型的本质就是参数化类型,也就是让数据类型作为参数传递,其中E相当于形式参数负责占位,而使用集合时<>中的数据类型相当于实际参数,用于给形式参数E进行初始化,从而使得集合中所有的E被实际参数替换,由于实际参数可以传递各种各样广泛的数据类型,因此得名为泛型。
    集合类库 - 图3

    自定义泛型接口

    泛型接口和普通接口的区别就是后面添加了类型参数列表,可以有多个类型参数,如:

    自定义泛型类

  • 泛型类和普通类的区别就是类名后面添加了类型参数列表,可以有多个类型参数,如:等。

  • 实例化泛型类时应该指定具体的数据类型,并且是引用数据类型而不是基本数据类型。
  • 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型。
  • 子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型。

    自定义泛型方法

  • 泛型方法就是我们输入参数的时候,输入的是泛型参数,而不是具体的参数。我们在调用这个泛型

  • 方法的时需要对泛型参数进行实例化。
  • 泛型方法的格式:
    • [访问权限] <泛型> 返回值类型 方法名([泛型标识 参数名称]) { 方法体; }
  • 在静态方法中使用泛型参数的时候,需要我们把静态方法定义为泛型方法。
    ```java public static void printArr(T1[] arr){ for (T1 tt :arr) {
    1. System.out.println("tt=" + tt);
    } }
  1. <a name="ajToJ"></a>
  2. ## 泛型在继承上的体现
  3. 如果B是A的一个子类或子接口,而G是具有泛型声明的类或接口,则G并不是G的子类型!<br />比如:String是Object的子类,但是List并不是List的子类。
  4. <a name="ybQga"></a>
  5. ## 通配符的使用
  6. 有时候我们希望传入的类型在一个指定的范围内,此时就可以使用泛型通配符了。<br />如:之前传入的类型要求为Integer类型,但是后来业务需要Integer的父类Number类也可以传入。<br />泛型中有三种通配符形式:
  7. - <?> 无限制通配符:表示我们可以传入任意类型的参数。<br />
  8. - <? extends E> 表示类型的上界是E,只能是E或者是E的子类。<br />
  9. - <? super E> 表示类型的下界是E,只能是E或者是E的父类。<br />
  10. ```java
  11. package com.lagou.task15;
  12. import java.util.LinkedList;
  13. import java.util.List;
  14. /**
  15. * @author lijing
  16. * @date 2020/10/10 14:04
  17. * @description
  18. */
  19. public class GenericTest {
  20. public static void main(String[] args) {
  21. //1.声明两个List类型的集合测试
  22. List<Animal> lt1=new LinkedList<>();
  23. List<Dog> lt2=new LinkedList<>();
  24. //试图将lt2的数值赋值给lt1,也就是List<Dog>类型向List<Animal>类型的转换
  25. //lt1=lt2; Error 类型之间不具备父子关系
  26. System.out.println("-------------------");
  27. //2.视同通配符作为泛型类型的公共父类
  28. List<?> lt3=new LinkedList<>();
  29. lt3=lt1;//可以发生List<Animal>类型到List<?>类型的转换
  30. lt3=lt2;//可以发生List<Dog>类型到List<?>类型的转换
  31. //向公共父类中添加元素和获取元素
  32. // lt3.add(new Animal());Error 不能存放Animal类型的对象
  33. // lt3.add(new Dog());Error 不能存放Dog类型的对象 不支持元素的添加,不知道你添加的类型,如果更小就不会了
  34. Object o=lt3.get(0);//ok 支持元素的获取操作,全部当做Object类型
  35. System.out.println("-------------------");
  36. //有限制的通配符
  37. List<? extends Animal> lt4=new LinkedList<>();//最大是Animal
  38. // lt4.add(new Animal())//Error
  39. // lt4.add(new Dog()); Error
  40. // lt4.add(new Object());Error
  41. Animal animal = lt4.get(0);
  42. System.out.println("-------------------");
  43. List<? super Animal> lt5=new LinkedList<>();//最小是Animal
  44. lt5.add(new Animal());
  45. lt5.add(new Dog());
  46. // lt5.add(new Object());Error 超过了Animal类型的范围
  47. Object object = lt5.get(0);
  48. }
  49. }

Set集合(熟悉)

java.util.Set集合是Collection集合的子集合,与List集合平级。
该集合中元素没有先后放入次序且不允许重复。
该集合的主要实现类是:HashSet类 和 TreeSet类以及LinkedHashSet类
其中HashSet类的底层是采用哈希表进行数据管理的。
其中TreeSet类的底层是采用红黑树进行数据管理的。
其中LinkedHashSet类与HashSet类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
案例题目
准备一个Set集合指向HashSet对象,向该集合中添加元素”two”并打印,再向集合中添加元
素”one”并打印,再向集合中添加元素”three”并打印,再向集合中添加”one”并打印。

  1. package com.lagou.task15;
  2. import java.util.HashSet;
  3. import java.util.LinkedHashSet;
  4. import java.util.Set;
  5. /**
  6. * @author lijing
  7. * @date 2020/10/10 14:26
  8. * @description
  9. */
  10. public class HashSetTest {
  11. public static void main(String[] args) {
  12. //1.声明一个Set类型的引用指向HashSet类型的对象
  13. Set<String> s1=new HashSet<>();//无序不重复
  14. // Set<String> s1=new LinkedHashSet<>();//有序不重复
  15. System.out.println("s1=" + s1);
  16. System.out.println("----------------------------");
  17. boolean b1 = s1.add("two");
  18. System.out.println("b1=" + b1);
  19. System.out.println("s1=" + s1);
  20. b1 = s1.add("one");
  21. System.out.println("b1=" + b1);
  22. System.out.println("s1=" + s1);
  23. b1 = s1.add("three");
  24. System.out.println("b1=" + b1);
  25. System.out.println("s1=" + s1);
  26. b1 = s1.add("two");
  27. System.out.println("b1=" + b1);
  28. System.out.println("s1=" + s1);
  29. //验证元素不能重复
  30. }
  31. }

元素放入HashSet集合的原理

  • 使用元素调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算出该元素在数组中的索引位置。
  • 若该位置没有元素,则将该元素直接放入即可。
  • 若该位置有元素,则使用新元素与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
  • 若新元素与已有元素的哈希值相同,则使用新元素调用equals方法与已有元素依次比较。
  • 若相等则添加元素失败,否则将元素直接放入即可。

集合类库 - 图4
思考:为什么要求重写equals方法后要重写hashCode方法呢?
解析:
当两个元素调用equals方法相等时证明这两个元素相同,重写hashCode方法后保证这两个元
素得到的哈希码值相同,由同一个哈希算法生成的索引位置相同,此时只需要与该索引位置已有元素比较即可,从而提高效率并避免重复元素的出现。

TreeSet集合的概念

  • 由于TreeSet集合的底层采用红黑树进行数据的管理,当有新元素插入到TreeSet集合时,需要使用新元素与集合中已有的元素依次比较来确定新元素的合理位置。
  • 比较元素大小的规则有两种方式:

使用元素的自然排序规则进行比较并排序,让元素类型实现java.lang.Comparable接口;
使用比较器规则进行比较并排序,构造TreeSet集合时传入java.util.Comparator接口;

  • 自然排序的规则比较单一,而比较器的规则比较多元化,而且比较器优先于自然排序;
    ```java package com.lagou.task15;

import java.util.Comparator; import java.util.Set; import java.util.TreeSet;

/**

  • @author lijing
  • @date 2020/10/10 14:39
  • @description */ public class TreeSetTest { public static void main(String[] args) {

    1. //1.准备一个TreeSet集合并打印
    2. Set<String> s1=new TreeSet<>();
    3. System.out.println("s1=" + s1);
    4. //2.向集合中添加String类型的对象并打印
    5. boolean b1 = s1.add("aa");
    6. System.out.println("b1=" + b1);
    7. System.out.println("s1=" + s1);
    8. b1 = s1.add("cc");
    9. System.out.println("b1=" + b1);
    10. System.out.println("s1=" + s1);
    11. b1 = s1.add("bb");
    12. System.out.println("b1=" + b1);
    13. //由于TreeSet集合的底层是采用红黑树实现的,因此元素有大小次序,默认是从小到大打印
    14. System.out.println("s1=" + s1);
    15. System.out.println("---------------------------------");
    16. //4.准备一个比较器对象作为参数传递给构造方法
    17. //匿名内部类 :接口/父类类型 引用变量名 = new 接口/父类(){方法的重写}
    18. /*Comparator<Student> c1=new Comparator<Student>() {
    19. @Override
    20. public int compare(Student o1, Student o2) {//o1新增加的对象,o2表示集合中已有的对象

    // return o1.getAge()-o2.getAge();//按照年龄排序比较

    1. return o2.getAge()-o1.getAge();
    2. }
    3. };*/

    // 从Java8开始支持Lambda表达式:(参数列表)->{方法体}

    1. Comparator<Student> c1=(Student o1,Student o2)->{return o1.getAge()-o2.getAge();};
    2. //3.准备一个TreeSet集合并放入Student类型的对象并打印
    3. Set<Student> s2=new TreeSet<>();

    // Set s2=new TreeSet<>(c1);

    1. s2.add(new Student("张飞",30));
    2. s2.add(new Student("关羽",35));
    3. s2.add(new Student("刘备",40));
    4. s2.add(new Student("刘备",38));
    5. System.out.println("s2="+s2);

    } }

  1. <a name="YPnEc"></a>
  2. # Map集合(重点)
  3. <a name="FNrrt"></a>
  4. ## 基本概念
  5. - java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,其中类型参数如下:
  6. - K - 此映射所维护的键(Key)的类型,相当于目录。<br />
  7. - V - 映射值(Value)的类型,相当于内容。<br />
  8. - 该集合中key是不允许重复的,而且一个key只能对应一个value。<br />
  9. - 该集合的主要实现类有:HashMap类、TreeMap类、LinkedHashMap类、Hashtable类、Properties类。
  10. - 其中HashMap类的底层是采用哈希表进行数据管理的。<br />
  11. - 其中TreeMap类的底层是采用红黑树进行数据管理的。<br />
  12. - 其中LinkedHashMap类与HashMap类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。<br />
  13. - 其中Hashtable类是古老的Map实现类,与HashMap类相比属于线程安全的类,且不允许null作为key或者value的数值。<br />
  14. - 其中Properties类是Hashtable类的子类,该对象用于处理属性文件,key和value都是String类型的。<br />
  15. - Map集合是面向查询优化的数据结构, 在大数据量情况下有着优良的查询性能。<br />
  16. - 经常用于根据key检索value的业务场景。<br />
  17. | <br />V put(K key, V value) | <br />将Key-Value对存入Map,若集合中已经包含该Key,则替换该Key所对应的Value,返回值为该Key原来所对应的Value,若没有则返回null |
  18. | --- | --- |
  19. | <br />V get(Object key) | <br />返回与参数Key所对应的Value对象,如果不存在则返回null |
  20. | <br />boolean containsKey(Object key); | <br />判断集合中是否包含指定的Key |
  21. | <br />boolean containsValue (Object value); | <br />判断集合中是否包含指定的Value |
  22. | <br />V remove(Object key) | <br />根据参数指定的key进行删除 |
  23. | <br />Set keySet() | <br />返回此映射中包含的键的Set视图 |
  24. | <br />Collection values() | <br />返回此映射中包含的值的Collection视图 |
  25. | <br />Set<Map.Entry<K,V>> entrySet() | <br />返回此映射中包含的映射的Set视图 |
  26. ```java
  27. package com.lagou.task15;
  28. import java.util.Collection;
  29. import java.util.HashMap;
  30. import java.util.Map;
  31. import java.util.Set;
  32. /**
  33. * @author lijing
  34. * @date 2020/10/10 15:42
  35. * @description
  36. */
  37. public class MapTest {
  38. public static void main(String[] args) {
  39. //1.准备一个Map集合并打印
  40. Map<String,String> m1=new HashMap<>();
  41. //自动调用toString方法,默认打印格式为:{key1=value1,key2=value2,...}
  42. System.out.println("m1=" + m1);
  43. //2.向集合中添加元素并打印
  44. String str1=m1.put("1","one");
  45. System.out.println("原来的value数值为:" + str1);
  46. System.out.println("m1=" + m1);
  47. str1=m1.put("3","three");
  48. System.out.println("原来的value数值为:" + str1);
  49. System.out.println("m1=" + m1);
  50. str1=m1.put("2","two");
  51. System.out.println("原来的value数值为:" + str1);
  52. System.out.println("m1=" + m1);
  53. //实现了修改的功能
  54. str1=m1.put("1","eleven");
  55. System.out.println("原来的value数值为:" + str1);
  56. System.out.println("m1=" + m1);
  57. System.out.println("-----------------------------");
  58. //4.实现集合中元素的查找操作
  59. boolean b1 = m1.containsKey("11");
  60. System.out.println("b1=" + b1);//false
  61. b1 = m1.containsKey("1");
  62. System.out.println("b1=" + b1);//true
  63. b1=m1.containsValue("one");
  64. System.out.println("b1=" + b1);//false
  65. b1=m1.containsValue("eleven");
  66. System.out.println("b1=" + b1);//true
  67. String str2 = m1.get("5");
  68. System.out.println("str2=" + str2);//null
  69. str2 = m1.get("3");
  70. System.out.println("str2=" + str2);//three
  71. System.out.println("-------------------------");
  72. //4.实现集合中元素的删除操作
  73. str2 = m1.remove("1");
  74. System.out.println("被删除的value是:" + str2);
  75. System.out.println("m1=" + m1);
  76. System.out.println("-------------------------");
  77. //5.获取Map集合中所有的key并组成set试图
  78. Set<String> s1 = m1.keySet();
  79. for (String ts :s1) {
  80. System.out.println(ts+"="+m1.get(ts));
  81. }
  82. System.out.println("-------------------------");
  83. //6.获取Map集合中所有的value并组成Collection视图
  84. Collection<String> co = m1.values();
  85. for (String ts :co) {
  86. System.out.println("ts=" + ts);
  87. }
  88. System.out.println("-------------------------");
  89. //7.获取Map集合中所有的键值对并组成Set视图
  90. Set<Map.Entry<String, String>> entries = m1.entrySet();
  91. for (Map.Entry<String, String> me :entries) {
  92. System.out.println(me);
  93. }
  94. }
  95. }

元素放入HashMap集合的原理

  • 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置。
  • 若该位置没有元素,则将该键值对直接放入即可。
  • 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
  • 若key与已有元素的哈希值相同,则使用key调用equals方法与已有元素依次比较。
  • 若相等则将对应的value修改,否则将键值对直接放入即可。

    相关的常量

  • DEFAULT_INITIAL_CAPACITY : HashMap的默认容量是16。

  • DEFAULT_LOAD_FACTOR:HashMap的默认加载因子是0.75。
  • threshold:扩容的临界值,该数值为:容量*填充因子,也就是12。
  • TREEIFY_THRESHOLD:若Bucket中链表长度大于该默认值则转化为红黑树存储,数值为8。
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,该数值是64。

    Collections类

    |
    static > T max(Collection<? extends T> coll) |
    根据元素的自然顺序返回给定集合的最大元素 | | —- | —- | |
    static T max(Collection<? extends T> coll,Comparator<?super T> comp) |
    根据指定比较器引发的顺序返回给定集合的最大元素 | |
    static > T min(Collection<? extends T> coll) |
    根据元素的自然顺序返回给定集合的最小元素 | |
    static T min(Collection<? extends T> coll, Comparator<?super T> comp) |
    根据指定比较器引发的顺序返回
    给定集合的最小元素 | |
    static void copy(List<? super T> dest, List<? extends T>src) |
    将一个列表中的所有元素复制到
    另一个列表中 | |
    static void reverse(List<?> list) |
    反转指定列表中元素的顺序 | |
    static void shuffle(List<?> list) |
    使用默认的随机源随机置换指定的列表 | |
    static > void sort(List list) |
    根据其元素的自然顺序将指定列表按升序排序 | |
    static void sort(List list, Comparator<? super T> c) |
    根据指定比较器指定的顺序对指定列表进行排序 | |
    static void swap(List<?> list, int i, int j) |
    交换指定列表中指定位置的元素 |
  1. package com.lagou.task15;
  2. import java.util.*;
  3. /**
  4. * @author lijing
  5. * @date 2020/10/10 16:05
  6. * @description
  7. */
  8. public class CollectionsTest {
  9. public static void main(String[] args) {
  10. //1.准备一个集合类
  11. List<Integer> lt1 = Arrays.asList(10, 20, 30, 40, 50, 60);
  12. //2.实现集合中的各种操作
  13. System.out.println("集合中的最大值是:" + Collections.max(lt1));//60
  14. System.out.println("集合中的最大值是:" + Collections.min(lt1));//10
  15. //实现集合中元素的翻转
  16. Collections.reverse(lt1);
  17. System.out.println("反转后lt1=" + lt1);
  18. //实现两个元素的交换
  19. Collections.swap(lt1,0,4);
  20. System.out.println("交换后lt1=" + lt1);
  21. //实现元素的排序
  22. Collections.sort(lt1);
  23. System.out.println("排序后lt1=" + lt1);
  24. //随机置换
  25. Collections.shuffle(lt1);
  26. System.out.println("随机置换后:lt1" + lt1);
  27. //实现集合间元素的拷贝
  28. // List<Integer> lt2=new ArrayList<>();
  29. List<Integer> lt2=Arrays.asList(new Integer[10]);
  30. //表示将lt1中的元素拷贝到lt2中
  31. System.out.println("lt1的个数为:" + lt1.size());//6
  32. System.out.println("lt2的个数为:" + lt2.size());//0
  33. /*if (srcSize > dest.size()) 6>0
  34. throw new IndexOutOfBoundsException("Source does not fit in dest");*/
  35. Collections.copy(lt2,lt1);
  36. System.out.println("lt2=" + lt2);
  37. // Source does not fit in dest
  38. }
  39. }