一、集合框架

1.1 概述

集合:集合是Java中提供的一种容器,可以用来存储多个数据。

集合和数组:

  • 数组的长度是固定的。集合的长度是可变的。
  1. int[] arr = new int[10];
  • 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一样,在开发中一般当对象多的时候,使用集合进行存储。

1.2 集合框架

学习顶层:学习顶层接口/抽象类中共性的方法,所有的子类都可以使用。

使用底层:上层不是接口就是抽象类,无法创建对象使用,需要使用底层的子类创建对象使用

集合 - 图1

二、Collection接口

java.util.Collection

  • boolean add(E e) 确保此集合包含指定的元素(可选操作)。
  • void clear() 从此集合中删除所有元素(可选操作)。
  • boolean contains(Object o) 如果此集合包含指定的元素,则返回 true 。
  • boolean isEmpty() 如果此集合不包含元素,则返回 true 。
  • boolean remove(Object o) 从该集合中删除指定元素的单个实例(如果存在)(可选操作)。
  • int size() 返回此集合中的元素数。
  • Object[] toArray() 返回一个包含此集合中所有元素的数组。

三、Iterator迭代器接口

java.util.Iterator 接口:迭代器(对集合进行遍历)。

3.1 常用方法

  1. boolean hasNext() //如果仍有元素可以迭代,则返回true。判断集合中还有没有下一个元素,有就返回true,没有则返回false
  2. E next() //返回迭代的下一个元素

Collection接口中有一个方法iterator(),这个方法返回的就是迭代器的实现类对象

  1. Iterator<E> iterator() 返回在次Collection的元素上进行迭代的迭代器

使用步骤:

① 使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)。

② 使用Iterator接口中的方法hasNext判断还有没有下一个元素。

③ 使用Iterator接口中的方法next取出集合中的下一个元素

注意:Iterator接口是有泛型的迭代器的泛型跟着集合走。集合什么泛型,他就什么泛型

实现原理:

集合 - 图2

3.2 增强for循环

底层使用的也是迭代器,只是使用for循环的格式,简化了迭代器的书写(JDK1.5以后的新特性)。

  1. for(集合/数组的数据类型 变量名:集合名/数组名){
  2. //...
  3. }

四、泛型

4.1 概念

泛型是一种未知的数据类型,但我们不知道使用什么数据类型的时候,就用泛型。

也可以看成一种变量,用来接收数据类型。

集合 - 图3

创建集合对象,不使用泛型时:

  • 好处:集合不适用泛型,默认的类型就是Object类型,可以存储任意类型的数据

  • 弊端:不安全,会引发异常。

创建集合对象,使用泛型:

  • 好处:避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型;把运行期异常(代码运行之后抛出的异常),提升到了编译期(写代码的时候报错)。
  • 弊端:泛型是什么类型,只能存储什么类型。

4.2 含有泛型的类

在定义类时在类名后面加个,创建对象时声明E是什么类型即可。

  1. public class GenericClass<E> {
  2. private E name;
  3. public E getName() {
  4. return name;
  5. }
  6. public void setName(E name) {
  7. this.name = name;
  8. }
  9. }
  1. public class Demo02GenericClass {
  2. public static void main(String[] args) {
  3. //不写泛型默认为Object类型
  4. GenericClass gc = new GenericClass();
  5. gc.setName("test");
  6. Object obj = gc.getName();
  7. //创建GenericClass对象,泛型使用Integer类型
  8. GenericClass<Integer> gc2 = new GenericClass<>();
  9. gc2.setName(1);
  10. Integer name = gc2.getName();
  11. System.out.println(name);
  12. //创建GenericClass对象,泛型使用String类型
  13. GenericClass<String> gc3 = new GenericClass<>();
  14. gc3.setName("小明");
  15. String name1 = gc3.getName();
  16. System.out.println(name1);
  17. }
  18. }

4.3 含有泛型的方法

泛型定义在方法的 修饰符返回值 类型之间

  1. 修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){
  2. //方法体
  3. }

在调用时,要确认数据类型。

  1. public class GenericMethod {
  2. //定义一个含有泛型的方法
  3. public <M> void method01(M m){
  4. System.out.println(m);
  5. }
  6. }
  1. public class Demo03GenericMethod {
  2. public static void main(String[] args) {
  3. //创建GenericMethod对象
  4. GenericMethod gm = new GenericMethod();
  5. /*
  6. 调用含有泛型的方法method01
  7. 传递什么类型,泛型就是什么类型
  8. */
  9. gm.method01(10);
  10. gm.method01("abc");
  11. gm.method01(8.8);
  12. gm.method01(true);
  13. }
  14. }

4.4 含有泛型的接口

  1. public interface GenericInterface<I> {
  2. public abstract void method(I i);
  3. }

第一种使用方式 :定义接口的实现类,实现接口,指定接口的泛型。

  1. public class GenericInterfaceImpl1 implements GenericInterface<String>{
  2. @Override
  3. public void method(String s) {
  4. System.out.println(s);
  5. }
  6. }

第二种使用方式 :接口使用什么泛型,实现类就使用什么泛型,类跟着接口走,就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。

  1. // 这里的泛型必须保持一致为同一个名称(如:同为I),否则会报错
  2. public class GenericInterfaceImpl2<I> implements GenericInterface<I> {
  3. @Override
  4. public void method(I i) {
  5. System.out.println(i);
  6. }
  7. }
  1. public class Demo04GenericInterface {
  2. public static void main(String[] args) {
  3. //创建GenericInterfaceImpl1对象
  4. GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
  5. gi1.method("字符串");
  6. //创建GenericInterfaceImpl2对象
  7. GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
  8. gi2.method(10);
  9. GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
  10. gi3.method(8.8);
  11. }
  12. }

4.5 泛型通配符

① 概念
不能创建对象使用,只能作为方法的参数使用。

  1. public class Demo05Generic {
  2. public static void main(String[] args) {
  3. ArrayList<Integer> list01 = new ArrayList<>();
  4. list01.add(1);
  5. list01.add(2);
  6. ArrayList<String> list02 = new ArrayList<>();
  7. list02.add("a");
  8. list02.add("b");
  9. printArray(list01);
  10. printArray(list02);
  11. //ArrayList<?> list03 = new ArrayList<?>();//报错
  12. }
  13. /*
  14. 定义一个方法,能遍历所有类型的ArrayList集合
  15. 这时候我们不知道ArrayList集合使用什么数据类型,可以泛型的通配符?来接收数据类型
  16. 注意:
  17. 泛型是没有继承概念的,所以?不能用Object来代替
  18. */
  19. public static void printArray(ArrayList<?> list){
  20. //使用迭代器遍历集合
  21. Iterator<?> it = list.iterator();
  22. while(it.hasNext()){
  23. //it.next()方法,取出的元素是Object,可以接收任意的数据类型
  24. Object o = it.next();
  25. System.out.println(o);
  26. }
  27. }
  28. }

② 受限泛型

  • 泛型的上限限定:? extends E代表使用的泛型只能是E类型的子类/本身
  • 泛型的下限限定:? super E代表使用的泛型只能是E类型的父类/本身
  1. public class Demo06Generic {
  2. public static void main(String[] args) {
  3. Collection<Integer> list1 = new ArrayList<Integer>();
  4. Collection<String> list2 = new ArrayList<String>();
  5. Collection<Number> list3 = new ArrayList<Number>();
  6. Collection<Object> list4 = new ArrayList<Object>();
  7. getElement1(list1);
  8. //getElement1(list2);//报错
  9. getElement1(list3);
  10. //getElement1(list4);//报错
  11. //getElement2(list1);//报错
  12. //getElement2(list2);//报错
  13. getElement2(list3);
  14. getElement2(list4);
  15. /*
  16. 类与类之间的继承关系
  17. Integer extends Number extends Object
  18. String extends Object
  19. */
  20. }
  21. // 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
  22. public static void getElement1(Collection<? extends Number> coll){}
  23. // 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
  24. public static void getElement2(Collection<? super Number> coll){}
  25. }

五、List接口

java.util.List 有序、有索引、允许存储相同的元素

5.1 常用方法

  1. public void add(int index,E element) 将指定的元素添加到该集合中的指定位置上
  2. public E get(int index) 返回集合中指定位置的元素
  3. public E remove(int index) 移除列表中指定位置的元素,返回的是被移除的元素
  4. public E set(int index,E element) 用指定元素替换集合中指定位置的元素,返回更新前的元素

5.2 LinkedList

java.util.LinkedList

  • ArrayList集合:底层是 数组结构 ,多线程,查询快,增删慢。
  • LinkedList集合:① 底层是一个 链表结构 ,多线程,查询慢,增删快;② 里面包含了大量操作首尾元素的方法。

注意:使用LinkedList集合特有的方法,不能使用多态。

① 添加相关的方法

  1. public void addFirst(E e) 将指定元素添加到此列表的开头,此方法等效于public void push(E e)方法
  2. public void addLast(E e) 将指定元素添加到此列表的结尾,此方法等效于add()

② 获取相关的方法

  1. public E getFirst() 返回列表的第一个元素
  2. public E getLast() 返回列表的最后一个元素

注意:如果集合中无元素,会报错。

③ 移除相关的方法

  1. public E removeFirst() 移除并返回此列表的第一个元素,等效于public E pop()
  2. public E removeLast() 移除并返回此列表的最后一个元素

5.3 Vector

底层是 数组结构 ,单线程,速度慢,后来被ArrayList取代。

六 、Set接口

java.util.Set

6.1 特点

① 不允许存储重复的元素。

② 没有索引,没有带索引的方法,也不能使用普通的for循环。

6.2 hashSet

6.2.1 特点

① 不允许存储重复的元素。

② 没有索引,没有带索引的方法,也不能使用普通的for循环。

③ 无序集合,存储元素和取出元素的顺序有可能不一致。

④ 底层是一个哈希表结构(查询的速度非常快)。

6.2.2 哈希值

哈希值是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来的地址,不是数据实际存储的物理地址)。

在Object类中有一个方法,可以获取对象的hash值

int hashCode()返回该对象的哈希码值

对象的地址值就是用的hashCode()方法返回的哈希码的十六进制,但是字符串String类重写了hashCode方法。

6.2.3 哈希表

在jdk1.8版本之前,哈希表 = 数组 + 链表

在jdk1.8版本之后:

哈希表 = 数组 +链表

哈希表 = 数组 + 红黑树(提高查询的速度)

集合 - 图4

Set集合不允许存储重复元素的原理:

集合 - 图5

6.2.4 存储引用类型

要求:同名和同年龄的人,视为同一个人,只能在Hashset集合中存储一次。

则必须重写hashCode方法和equals方法。

  1. import java.util.Objects;
  2. public class Person {
  3. private String name;
  4. private int age;
  5. public Person() {
  6. }
  7. public Person(String name, int age) {
  8. this.name = name;
  9. this.age = age;
  10. }
  11. @Override
  12. public boolean equals(Object o) {
  13. if (this == o) return true;
  14. if (o == null || getClass() != o.getClass()) return false;
  15. Person person = (Person) o;
  16. return age == person.age &&
  17. Objects.equals(name, person.name);
  18. }
  19. @Override
  20. public int hashCode() {
  21. return Objects.hash(name, age);
  22. }
  23. @Override
  24. public String toString() {
  25. return "Person{" +
  26. "name='" + name + '\'' +
  27. ", age=" + age +
  28. '}';
  29. }
  30. public String getName() {
  31. return name;
  32. }
  33. public void setName(String name) {
  34. this.name = name;
  35. }
  36. public int getAge() {
  37. return age;
  38. }
  39. public void setAge(int age) {
  40. this.age = age;
  41. }
  42. }
  1. public class Demo03HashSetSavePerson {
  2. public static void main(String[] args) {
  3. //创建HashSet集合存储Person
  4. HashSet<Person> set = new HashSet<>();
  5. Person p1 = new Person("小美女",18);
  6. Person p2 = new Person("小美女",18);
  7. Person p3 = new Person("小美女",19);
  8. System.out.println(p1.hashCode());//1967205423
  9. System.out.println(p2.hashCode());//42121758
  10. System.out.println(p1==p2);//false
  11. System.out.println(p1.equals(p2));//true,若不重写,Object类中的equals方法和“==”是一样的,比较的都是内存地址值
  12. set.add(p1);
  13. set.add(p2);
  14. set.add(p3);
  15. System.out.println(set);
  16. }
  17. }

6.3 LinkedHashSet

java.util.LinkedHashSet 集合继承了HashSet集合

① 底层是一个哈希表(数组+链表/红黑树)+ 链表,比HashSet多了一条链表(记录元素的存储顺序),保证元素有序。

② 有序,不允许重复

七、可变参数

JDK1.5之后的新特性

7.1 使用格式

  • 当方法的参数列表数据类型已经确定,但是参数个数不确定,就可以使用可变参数。
  1. 修饰符 返回值类型 方法名(数据类型...变量名){}

7.2 原理

可变参数的底层就是一个数组,根据传递参数个数的不同,会创建不同长度的数组,来存储这些参数,传递的参数个数,可以是0个(不传递),1个,2个…多个。

这样这个参数列表中的变量名就就变成了相应类型的数组。

  1. public static int add(int...arr){
  2. //定义一个初始化的变量,记录累加求和
  3. int sum = 0;
  4. //遍历数组,获取数组中的每一个元素
  5. for (int i : arr) {
  6. //累加求和
  7. sum += i;
  8. }
  9. //把求和结果返回
  10. return sum;
  11. }

7.3 注意

① 一个方法的参数列表只能有一个可变参数

② 如果一个方法的参数有多个,那么可变参数必须写在参数列表的末尾。

7.4 特殊写法

  1. public static void method(Object...obj){}//这里可以接收任意数据类型的参数

八、Collections工具类

java.util.Collections

  1. public static <T> boolean addAll(Collection<T> c,T...elements)//往集合中添加一些元素
  2. public static void shuffle(List<?> list) //打乱集合顺序

排序方法

  1. public static <T> void sort(List<T> list) //将集合中的元素按照默认规则进行排序

这里的 T 类型的数据,必须实现Comparable接口,并在类中重写接口中的方法compareTo定义。

Comparable接口的排序规则:

  • 自己(this) - 参数 //这是升序
  • 参数 - 自己(this)//这是降序
  1. public class Person implements Comparable<Person>{
  2. private String name;
  3. private int age;
  4. public Person() {
  5. }
  6. public Person(String name, int age) {
  7. this.name = name;
  8. this.age = age;
  9. }
  10. @Override
  11. public String toString() {
  12. return "Person{" +
  13. "name='" + name + '\'' +
  14. ", age=" + age +
  15. '}';
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public int getAge() {
  24. return age;
  25. }
  26. public void setAge(int age) {
  27. this.age = age;
  28. }
  29. //重写排序的规则
  30. @Override
  31. public int compareTo(Person o) {
  32. //return 0;//认为元素都是相同的
  33. //自定义比较的规则,比较两个人的年龄(this,参数Person)
  34. //return this.getAge() - o.getAge();//年龄升序排序
  35. return o.getAge() - this.getAge();//年龄降序排序
  36. }
  37. }
  1. public class Demo02Sort {
  2. public static void main(String[] args) {
  3. ArrayList<Integer> list01 = new ArrayList<>();
  4. list01.add(1);
  5. list01.add(3);
  6. list01.add(2);
  7. System.out.println(list01);//[1, 3, 2]
  8. //public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
  9. Collections.sort(list01);//默认是升序
  10. System.out.println(list01);//[1, 2, 3]
  11. ArrayList<String> list02 = new ArrayList<>();
  12. list02.add("a");
  13. list02.add("c");
  14. list02.add("b");
  15. System.out.println(list02);//[a, c, b]
  16. Collections.sort(list02);
  17. System.out.println(list02);//[a, b, c]
  18. ArrayList<Person> list03 = new ArrayList<>();
  19. list03.add(new Person("张三",18));
  20. list03.add(new Person("李四",20));
  21. list03.add(new Person("王五",15));
  22. System.out.println(list03);//[Person{name='张三', age=18}, Person{name='李四', age=20}, Person{name='王五', age=15}]
  23. Collections.sort(list03);
  24. System.out.println(list03);
  25. }
  26. }
  1. public static <T> void sort(List<T> list,Comparator<? super T>) //将集合中元素按照指定规则排序

Comparator 与 Comparable的区别

① Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较规则comparaTo方法

② Comparator:相当于找一个第三方的裁判,来进行比较(需要重写compare方法)

Comparator排序规则:

  • 第一个参数 - 第二个参数 //升序
  • 第二个参数 - 第一个参数 //降序
  1. public class Demo03Sort {
  2. public static void main(String[] args) {
  3. ArrayList<Integer> list01 = new ArrayList<>();
  4. list01.add(1);
  5. list01.add(3);
  6. list01.add(2);
  7. System.out.println(list01);//[1, 3, 2]
  8. Collections.sort(list01, new Comparator<Integer>() {
  9. //重写比较的规则
  10. @Override
  11. public int compare(Integer o1, Integer o2) {
  12. //return o1-o2;//升序
  13. return o2-o1;//降序
  14. }
  15. });
  16. System.out.println(list01);
  17. ArrayList<Student> list02 = new ArrayList<>();
  18. list02.add(new Student("a迪丽热巴",18));
  19. list02.add(new Student("古力娜扎",20));
  20. list02.add(new Student("杨幂",17));
  21. list02.add(new Student("b杨幂",18));
  22. System.out.println(list02);
  23. /*Collections.sort(list02, new Comparator<Student>() {
  24. @Override
  25. public int compare(Student o1, Student o2) {
  26. //按照年龄升序排序
  27. return o1.getAge()-o2.getAge();
  28. }
  29. });*/
  30. //扩展:了解
  31. Collections.sort(list02, new Comparator<Student>() {
  32. @Override
  33. public int compare(Student o1, Student o2) {
  34. //按照年龄升序排序
  35. int result = o1.getAge()-o2.getAge();
  36. //如果两个人年龄相同,再使用姓名的第一个字比较
  37. if(result==0){
  38. result = o1.getName().charAt(0)-o2.getName().charAt(0);
  39. }
  40. return result;
  41. }
  42. });
  43. System.out.println(list02);
  44. }
  45. }

九、Map接口

java.util.Map public interface Map<K,V>

9.1 特点

① Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)。

② Map集合中的元素,key和value的数据类型可以相同也可以不同。

③ Map集合中的元素,key是不允许重复的,value是可以重复的。

④ Map集合中的元素,key和value是一一对应的。

9.1.1 HashMap

java.util.HashMap集合 implements Map接口

① HashMap底层是哈希表,查询的速度特别快。

  1. JDK1.8之前:数组 + 单向链表。
  2. JDK1.8之后:数组 + 单向链表/红黑树(链表的长度超过8):提高查询速度

② HashMap是一个无序集合,存储元素和取出元素的顺序有可能不一致。

9.1.2 LinkedHashMap

java.util.LinkedHashMap extends HashMap

① LinkedHashMap集合底层是哈希表+链表(保证迭代顺序)

② LinkedHashMap集合是一个有序的集合,存储元素和取出元素的顺序是一致的。

9.2 Map常用方法

① put方法

  1. public V put(K key , V value) //把指定的键值对添加到Map集合中

如果key已存在,返回null;如果不存在,则用新的value替换旧的value,返回旧的value值。

② remove方法

  1. public V remove (Object key) //把指定的键值对元素,在Map中删除,返回被删除的元素的值

如果key存在,则返回被删除的值;如果key不存在,则返回null。

③ get方法

  1. public V get(Object key) //根据指定的键,在Map集合中获取对应的值

如果key存在,返回对应的value值;如果key不存在,则返回null。

④ containsKey方法

  1. boolean containsKey(Object key) //是否存在指定key

如果key存在,返回true;如果key不存在,则返回false。

⑤ keySet方法

  1. Set<K> keySet() //返回次映射中包含的键的Set集合

9.3 Map的遍历

9.3.1 keySet()

Map集合的第一种遍历方式,通过键找值的方式:

  1. public class Demo02KeySet {
  2. public static void main(String[] args) {
  3. //创建Map集合对象
  4. Map<String,Integer> map = new HashMap<>();
  5. map.put("赵丽颖",168);
  6. map.put("杨颖",165);
  7. map.put("林志玲",178);
  8. //1.使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
  9. Set<String> set = map.keySet();
  10. //2.遍历set集合,获取Map集合中的每一个key
  11. //使用迭代器遍历Set集合
  12. Iterator<String> it = set.iterator();
  13. while (it.hasNext()){
  14. String key = it.next();
  15. //3.通过Map集合中的方法get(key),通过key找到value
  16. Integer value = map.get(key);
  17. System.out.println(key+"="+value);
  18. }
  19. System.out.println("-------------------");
  20. //使用增强for遍历Set集合
  21. for(String key : set){
  22. //3.通过Map集合中的方法get(key),通过key找到value
  23. Integer value = map.get(key);
  24. System.out.println(key+"="+value);
  25. }
  26. System.out.println("-------------------");
  27. //使用增强for遍历Set集合
  28. for(String key : map.keySet()){
  29. //3.通过Map集合中的方法get(key),通过key找到value
  30. Integer value = map.get(key);
  31. System.out.println(key+"="+value);
  32. }
  33. }
  34. }

9.3.2 entrySet()

Entry是Map的内部类

  1. Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的Set集合

Map集合的第二种遍历方式,通过Entry对象遍历:

  1. public class Demo03EntrySet {
  2. public static void main(String[] args) {
  3. //创建Map集合对象
  4. Map<String,Integer> map = new HashMap<>();
  5. map.put("赵丽颖",168);
  6. map.put("杨颖",165);
  7. map.put("林志玲",178);
  8. //1.使用Map集合中 的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
  9. Set<Map.Entry<String, Integer>> set = map.entrySet();
  10. //2.遍历Set集合,获取每一个Entry对象
  11. //使用迭代器遍历Set集合
  12. Iterator<Map.Entry<String, Integer>> it = set.iterator();
  13. while(it.hasNext()){
  14. Map.Entry<String, Integer> entry = it.next();
  15. //3.使用Entry对象中的方法getKey()和getValue()获取键与值
  16. String key = entry.getKey();
  17. Integer value = entry.getValue();
  18. System.out.println(key+"="+value);
  19. }
  20. System.out.println("-----------------------");
  21. for(Map.Entry<String,Integer> entry:set){
  22. //3.使用Entry对象中的方法getKey()和getValue()获取键与值
  23. String key = entry.getKey();
  24. Integer value = entry.getValue();
  25. System.out.println(key+"="+value);
  26. }
  27. }
  28. }

9.4 存储引用类型

Map集合保证key是唯一的:

作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一。

  1. import java.util.Objects;
  2. public class Person {
  3. private String name;
  4. private int age;
  5. public Person() {
  6. }
  7. public Person(String name, int age) {
  8. this.name = name;
  9. this.age = age;
  10. }
  11. @Override
  12. public String toString() {
  13. return "Person{" +
  14. "name='" + name + '\'' +
  15. ", age=" + age +
  16. '}';
  17. }
  18. @Override
  19. public boolean equals(Object o) {
  20. if (this == o) return true;
  21. if (o == null || getClass() != o.getClass()) return false;
  22. Person person = (Person) o;
  23. return age == person.age &&
  24. Objects.equals(name, person.name);
  25. }
  26. @Override
  27. public int hashCode() {
  28. return Objects.hash(name, age);
  29. }
  30. public String getName() {
  31. return name;
  32. }
  33. public void setName(String name) {
  34. this.name = name;
  35. }
  36. public int getAge() {
  37. return age;
  38. }
  39. public void setAge(int age) {
  40. this.age = age;
  41. }
  42. }
  1. public class Demo01HashMapSavePerson {
  2. public static void main(String[] args) {
  3. show02();
  4. }
  5. private static void show02() {
  6. //创建HashMap集合
  7. HashMap<Person,String> map = new HashMap<>();
  8. //往集合中添加元素
  9. map.put(new Person("女王",18),"英国");
  10. map.put(new Person("秦始皇",18),"秦国");
  11. map.put(new Person("普京",30),"俄罗斯");
  12. map.put(new Person("女王",18),"毛里求斯");
  13. //使用entrySet和增强for遍历Map集合
  14. Set<Map.Entry<Person, String>> set = map.entrySet();
  15. for (Map.Entry<Person, String> entry : set) {
  16. Person key = entry.getKey();
  17. String value = entry.getValue();
  18. System.out.println(key+"-->"+value);
  19. }
  20. }
  21. private static void show01() {
  22. //创建HashMap集合
  23. HashMap<String,Person> map = new HashMap<>();
  24. //往集合中添加元素
  25. map.put("北京",new Person("张三",18));
  26. map.put("上海",new Person("李四",19));
  27. map.put("广州",new Person("王五",20));
  28. map.put("北京",new Person("赵六",18));
  29. //使用keySet加增强for遍历Map集合
  30. Set<String> set = map.keySet();
  31. for (String key : set) {
  32. Person value = map.get(key);
  33. System.out.println(key+"-->"+value);
  34. }
  35. }
  36. }

9.5 HashTable

java.util.HashTable 集合 implements Map 接口

  • 与HashMap的区别:

① 线程

HashTable:底层是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢。

HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快

② null

HashTable:不能存储null值、null键

HashMap(以及之前学的所有集合):可以存储null值、null键

  • 过时:

HashTable 和 Vector 一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了。

但是HashTable的子类Properties依然活跃,Properties集合是一个唯一和IO流相结合的集合。

十、练习

10.1 斗地主

集合 - 图6

  1. public class Dou {
  2. public static void main(String[] args) {
  3. ArrayList<String> card = saveCard();
  4. // System.out.println(card.size());
  5. // System.out.println(card);
  6. ArrayList<String> player1 = new ArrayList<>();
  7. ArrayList<String> player2 = new ArrayList<>();
  8. ArrayList<String> player3 = new ArrayList<>();
  9. ArrayList<String> bottom = new ArrayList<>();
  10. deliverCard(player1,player2,player3,bottom,card);
  11. System.out.println("刘德华:" + player1);
  12. System.out.println("周星驰:" + player2);
  13. System.out.println("古天乐:" + player3);
  14. System.out.println("底牌:" + bottom);
  15. // showCard(player1);
  16. // showCard(player2);
  17. // showCard(player3);
  18. // showCard(bottom);
  19. }
  20. //存牌并打乱
  21. public static ArrayList<String> saveCard(){
  22. ArrayList<String> card = new ArrayList<>();
  23. String[] color = {"♥","♦","♣","♠"};
  24. String[] tag = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
  25. for (int i = 0; i < color.length; i++) {
  26. for (int j = 0; j < tag.length; j++) {
  27. card.add(color[i] + tag[j]);
  28. }
  29. }
  30. card.add("大王");
  31. card.add("小王");
  32. Collections.shuffle(card);//随机打乱集合中的元素
  33. return card;
  34. }
  35. //发牌
  36. public static void deliverCard(ArrayList<String> player1,ArrayList<String> player2,ArrayList<String> player3,ArrayList<String> bottom,ArrayList<String> card){
  37. for (int i = 0; i < card.size(); i++) {
  38. if(i > 50){
  39. bottom.add(card.get(i));
  40. }
  41. else{
  42. if(i % 3 == 0){
  43. player1.add(card.get(i));
  44. }
  45. if(i % 3 == 1){
  46. player2.add(card.get(i));
  47. }
  48. if(i % 3 == 2){
  49. player3.add(card.get(i));
  50. }
  51. }
  52. }
  53. }
  54. //看牌
  55. public static void showCard(ArrayList<String> cardlist){
  56. for (int i = 0; i < cardlist.size(); i++) {
  57. System.out.print(cardlist.get(i) + "\t\t");
  58. }
  59. System.out.println();
  60. }
  61. }

10.2 字符个数

计算一个字符串中的每个字符个数

集合 - 图7

  1. public class CalcuChar {
  2. public static void main(String[] args) {
  3. Scanner sc = new Scanner(System.in);
  4. System.out.println("请输入一个字符串:");
  5. String s = sc.nextLine();
  6. HashMap<Character,Integer> map = new HashMap<>();
  7. char[] charArray = s.toCharArray();
  8. for (int i = 0; i < charArray.length; i++) {
  9. if(map.containsKey(charArray[i])){
  10. map.put(charArray[i],map.get(charArray[i]) + 1);
  11. }
  12. else map.put(charArray[i],1);
  13. }
  14. // Set<Map.Entry<Character,Integer>> en = map.entrySet();
  15. for (Map.Entry<Character,Integer> en:
  16. map.entrySet()) {
  17. System.out.print(en.getKey() + ":");
  18. System.out.print(en.getValue());
  19. System.out.println();
  20. }
  21. }
  22. }

10.3 斗地主升级版

集合 - 图8

  1. /*
  2. 斗地主综合案例:有序版本
  3. 1.准备牌
  4. 2.洗牌
  5. 3.发牌
  6. 4.排序
  7. 5.看牌
  8. */
  9. public class DouDiZhu {
  10. public static void main(String[] args) {
  11. //1.准备牌
  12. //创建一个Map集合,存储牌的索引和组装好的牌
  13. HashMap<Integer,String> poker = new HashMap<>();
  14. //创建一个List集合,存储牌的索引
  15. ArrayList<Integer> pokerIndex = new ArrayList<>();
  16. //定义两个集合,存储花色和牌的序号
  17. List<String> colors = List.of("♠", "♥", "♣", "♦");
  18. List<String> numbers = List.of("2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3");
  19. //把大王和小王存储到集合中
  20. //定义一个牌的索引
  21. int index = 0;
  22. poker.put(index,"大王");
  23. pokerIndex.add(index);
  24. index++;
  25. poker.put(index,"小王");
  26. pokerIndex.add(index);
  27. index++;
  28. //循环嵌套遍历两个集合,组装52张牌,存储到集合中
  29. for (String number : numbers) {
  30. for (String color : colors) {
  31. poker.put(index,color+number);
  32. pokerIndex.add(index);
  33. index++;
  34. }
  35. }
  36. //System.out.println(poker);
  37. //System.out.println(pokerIndex);
  38. /*
  39. 2.洗牌
  40. 使用Collections中的方法shuffle(List)
  41. */
  42. Collections.shuffle(pokerIndex);
  43. //System.out.println(pokerIndex);
  44. /*
  45. 3.发牌
  46. */
  47. //定义4个集合,存储玩家牌的索引,和底牌的索引
  48. ArrayList<Integer> player01 = new ArrayList<>();
  49. ArrayList<Integer> player02 = new ArrayList<>();
  50. ArrayList<Integer> player03 = new ArrayList<>();
  51. ArrayList<Integer> diPai = new ArrayList<>();
  52. //遍历存储牌索引的List集合,获取每一个牌的索引
  53. for (int i = 0; i <pokerIndex.size() ; i++) {
  54. Integer in = pokerIndex.get(i);
  55. //先判断底牌
  56. if(i>=51){
  57. //给底牌发牌
  58. diPai.add(in);
  59. }else if(i%3==0){
  60. //给玩家1发牌
  61. player01.add(in);
  62. }else if(i%3==1){
  63. //给玩家2发牌
  64. player02.add(in);
  65. }else if(i%3==2){
  66. //给玩家3发牌
  67. player03.add(in);
  68. }
  69. }
  70. /*
  71. 4.排序
  72. 使用Collections中的方法sort(List)
  73. 默认是升序排序
  74. */
  75. Collections.sort(player01);
  76. Collections.sort(player02);
  77. Collections.sort(player03);
  78. Collections.sort(diPai);
  79. /*
  80. 5.看牌
  81. 调用看牌的方法
  82. */
  83. lookPoker("刘德华",poker,player01);
  84. lookPoker("周润发",poker,player02);
  85. lookPoker("周星驰",poker,player03);
  86. lookPoker("底牌",poker,diPai);
  87. }
  88. /*
  89. 定义一个看牌的方法,提高代码的复用性
  90. 参数:
  91. String name:玩家名称
  92. HashMap<Integer,String> poker:存储牌的poker集合
  93. ArrayList<Integer> list:存储玩家和底牌的List集合
  94. 查表法:
  95. 遍历玩家或者底牌集合,获取牌的索引
  96. 使用牌的索引,去Map集合中,找到对应的牌
  97. */
  98. public static void lookPoker(String name,HashMap<Integer,String> poker,ArrayList<Integer> list){
  99. //输出玩家名称,不换行
  100. System.out.print(name+":");
  101. //遍历玩家或者底牌集合,获取牌的索引
  102. for (Integer key : list) {
  103. //使用牌的索引,去Map集合中,找到对应的牌
  104. String value = poker.get(key);
  105. System.out.print(value+" ");
  106. }
  107. System.out.println();//打印完每一个玩家的牌,换行
  108. }
  109. }

十一、JDK9的新特性

List、Set、Map接口添加了一个静态方法of,可以给集合一次性添加多个元素。

  1. static <E> List<E> of (E...elements)

使用前提: 当集合中存储的元素的个数已经确定了,不再改变时使用。

注意:

① of 方法只适用于List接口,Set接口,Map接口,不适用于这些接口的实现类。

② of 方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会出现异常。

③ Set接口和Map接口在调用方法时,不能有重复的元素,否则会抛出异常。

  1. public class Demo01JDK9 {
  2. public static void main(String[] args) {
  3. List<String> list = List.of("a", "b", "a", "c", "d");
  4. System.out.println(list);//[a, b, a, c, d]
  5. //list.add("w");//UnsupportedOperationException:不支持操作异常
  6. //Set<String> set = Set.of("a", "b", "a", "c", "d");//IllegalArgumentException:非法参数异常,有重复的元素
  7. Set<String> set = Set.of("a", "b", "c", "d");
  8. System.out.println(set);
  9. //set.add("w");//UnsupportedOperationException:不支持操作异常
  10. //Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20,"张三",19);////IllegalArgumentException:非法参数异常,有重复的元素
  11. Map<String, Integer> map = Map.of("张三", 18, "李四", 19, "王五", 20);
  12. System.out.println(map);//{王五=20, 李四=19, 张三=18}
  13. //map.put("赵四",30);//UnsupportedOperationException:不支持操作异常
  14. }
  15. }

十二、Debug调试

使用方式:

在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里),右键,选择Debug执行程序,程序就会停留在添加的第一个断点处。

执行程序:

  • f8:逐行执行程序
  • f7:进入到方法中
  • shift+f8:跳出方法
  • f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
  • ctrl+f2:退出debug模式,停止程序
  • Console:切换到控制台