`1 数据结构

常见的数据结构 : 栈堆 , 队列, 数组, 链表和红黑树

栈 : 它是运算受限的线性表, 其限制是仅允许在标的一端进行插入和删除操作, 不允许在其他任何位置进行添加, 查找, 删除等操作

  • 先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)
  • 栈的入口, 出口都是栈的顶端位置

压栈 : 就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置

弹栈 : 就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位置。

队列

队列 : 它也是运算受限的线性表, 其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。

  • 先进先出 (即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)

数组

数组 : 它是有序的元素序列, 数组是在内存中开辟一段连续的空间, 并在此空间存放元素; 每个元素都有对应的索引

特点 : 查找快, 通过索引, 可以快速访问指定位置的元素; 但是插入和删除操作费时

  • 指定索引位置增加元素 : 需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置
  • 指定索引位置删除元素 : 需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,原数组中指定索引位置元素不复制到新数组中

链表

链表 : linked list 是由一系列节点node(链表中每一个元素称为节点)组成, 节点可以在运行时动态生成, 每个节点包括两个部分: 一个是存储数据元素的数据域, 另外一个是存储指向下一个节点地址的指针域, 常见的链表还有单向链表和双向链表

特点 : 多个节点之间, 通过地址链接; 例如,多个人手拉手,每个人使用自己的右手拉住下个人的左手,依次类推,这样多个人就连在一起了

存储元素和取出元素的顺序有可能不一样

  • 查找元素慢 : 想查找某个元素, 需要通过链接的节点, 依次向后查找指定元素
  • 增删元素快 : 只需要修改链接下个元素的地址即可

红黑树

二叉树 : binary tree, 是每个节点不超过 2 的有序树; 就是一种类似于我们生活中树的结构, 只不过每个节点上都最多只能有两个子节点; 二叉树是每个节点最多有两个子树的树结构; 顶上的叫根节点, 两把被称为" 左子树"和" 右子树"

红黑树 : 本身就是一颗二叉查找数 , 将节点插入后, 该数仍然是一颗二叉查找数, 也就意味着, 树的键值仍然是有序的

红黑树的约束 :

  1. 节点可以是红色或者黑色的
  2. 根节点是黑色的
  3. 叶子节点(特指空节点)是黑色的
  4. 每个红色节点的子节点是黑色的
  5. 任何一个节点到每一个叶子节点的所有路径上黑色节点数相同

特点 : 速度特别快, 趋近平衡树, 查找叶子元素最少和最多次数不多于二倍

2 List接口

以下 接口 都是 Collection接口中的子类

java.util.List 接口继承自Collection 接口, 是单列集合的一个重要分支 , 习惯性地会将实现了List接口的对象称为List集合, 在List集合中允许出现重复的元素, 所有的元素是以一种线性方式进行存储的, 在程序中可以通过索引来访问集合中的指定元素; List集合还有一个特点就是元素有序, 即元素的存入顺序和取出顺序一致

特点:

  1. 它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的
  2. 它是一个带有索引的集合, 通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)
  3. 集合中可以有重复的元素, 铜鼓哦元素的equals方法,来比较是否为重复的元素

List接口中常用方法

List 作为Collection集合 的子接口, 不但继承了 Collection 接口中的全部方法, 而且还增加了一些根据元素索引来操作集合的特有方法

public void add(int index,E element) : 将指定的元素, 添加到该集合中的指定位置上

public E get(int index) : 返回集合中指定位置的元素

public E remove(int index) : 移除列表中指定位置的元素 , 返回的是被移除的元素

public E set(int index , E element) : 用指定元素替换集合中指定位置的元素, 返回值是更新前的元素

import java.util.ArrayList;
import java.util.List;public class Demo01List {public static void main(String[] args) {// 创建一个List集合对象, 多态List<String> list = new ArrayList<>();// 不加索引, 默认在list尾端加入list.add("a");list.add("b");list.add(1,"itcast");list.add("d");list.add("e");System.out.println(list);// 获取指定索引的元素System.out.println(list.get(1));// 移除指定索引的元素System.out.println(list.remove(2));// 更新指定索引的元素list.set(1,"HelloWorld");System.out.println(list);}
}

3 List的子类

ArrayList集合

java.util.ArrayList 集合数据存储的结构是数组结构; 元素增删慢, 查找快, 由于日常开发中使用最多的功能为查询数据, 遍历数据; 所以ArrayList 是常用的集合

LinkedList集合

java.util.LinkedList 集合数据存储的结构是链表结构, 方便元素添加, 删除的集合

LinkedList 是一个双向链表, 那么双向链表是什么样子的呢?

实际开发对一个集合元素的添加与删除经常涉及到首尾操作, LinkedList提供大量的首尾操作的方法

  • public void addFirst(E e) : 将指定元素插入到此列表的开头
  • public void addLast(E e) : 将指定元素插入到此列表的结尾
  • public void getFirst() : 获取此列表的第一个元素
  • public void getLast() : 获取此列表的最后一个元素
  • public void removeFirst() : 移除并返回此列表的第一个元素
  • public void removeLast() : 移除并返回此列表的最后一个元素
  • public E pop() : 从此列表中所表示的栈出弹出栈顶的一个元素
  • public E push() : 将元素推入到此列表所表示的栈
  • public boolean isEmpty() : 如果列表不包含元素, 则返回true

LinkedList 是 List的子类, List中的方法LinkedList都是可以使用的

 public static void main(String[] args) {LinkedList<String> link = new LinkedList<String>();//添加元素link.addFirst("abc1");link.addFirst("abc2");link.addFirst("abc3");link.addFirst("abc4");System.out.println(link);// 获取元素System.out.println(link.getFirst());System.out.println(link.getLast());// 删除元素System.out.println(link.removeFirst());System.out.println(link.removeLast());System.out.println(link);while (!link.isEmpty()) { //判断集合是否为空System.out.println(link.pop()); //弹出集合中的栈顶元素}System.out.println(link);}   public static void main(String[] args) {LinkedList<String> link = new LinkedList<String>();//添加元素link.addFirst("abc1");link.addFirst("abc2");link.addFirst("abc3");link.addFirst("abc4");System.out.println(link);// 获取元素System.out.println(link.getFirst());System.out.println(link.getLast());// 删除元素System.out.println(link.removeFirst());System.out.println(link.removeLast());System.out.println(link);while (!link.isEmpty()) { //判断集合是否为空System.out.println(link.pop()); //弹出集合中的栈顶元素}System.out.println(link);}

4 Set接口

java.util.Set 接口和 javautil.List 接口一样, 同样继承自 Collection接口, 它与Cllevtion接口中的方法基本一致, 并没有对Collection接口进行功能上的扩充, 只是比 Collection 接口国家严格了, 与List 接口的不同是, Set 接口中元素无序, 并且都会以某种规则保证存入的元素不会出现重复

Set 集合有多个子类, 这里介绍java.util.HashSet, java.util.LinkedHashSer

Set集合取出元素的方式可以采用 : 迭代器, 增强for

HashSet集合

java.util.HashSetSet接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet底层的实现其实是一个java.util.HashMap , 查询的速度非常快

HashSet 是根据对象的哈希值来确定元素在集合中存储的位置, 因此具有良好的存取和查找性能, 保证元素唯一性的方式依赖于 : hashCodeequals 方法

HashSet集合存储数据的结构(哈希表)

在JDK1.8之前, 哈希表底层此案有数组+链表实现, 即使用链表处理冲突, 同一hash值的链表都存储在一个链表里; 但是当位于一个桶中的元素较多, 即has值相等的元素较多时, 通过key值一次查找的效率降低; 在JDK1.8中, 哈希表采用数组+链表+红黑树实现, 当链表长度超过阈值( 8 )时,将链表转换为红黑树

总而言之, JDK1.8引入红黑树大程度优化了HashMap的性能, 那么对于我们来讲保证HashSet 集合元素的唯一, 其实就是根据对象的hashCodeequals方法来决定的, 如果我们往集合中存放自定义的对象, 那么保证其唯一, 就必须复写hashCode和equals方法建立属于当前对象的比较方式

HashSet存储自定义类型元素

给HashSet中存放自定义类型元素时, 需要重写对象的hashCodeequals方法, 建立自己的比较方式, 才能保证HashSet集合中的对象唯一

set集合不允许重复元素的原理

先调用hashcode方法判断哈希值是否相等, 若相等则为哈希冲突; 继续调用equals方法判断是否为同一对象

public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o)return true;if (o == null || getClass() != o.getClass())return false;Student student = (Student) o;return age == student.age &&Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}
}public class HashSetDemo2 {public static void main(String[] args) {//创建集合对象   该集合中存储 Student类型对象HashSet<Student> stuSet = new HashSet<Student>();//存储 Student stu = new Student("于谦", 43);stuSet.add(stu);stuSet.add(new Student("郭德纲", 44));stuSet.add(new Student("于谦", 43));stuSet.add(new Student("郭麒麟", 23));stuSet.add(stu);for (Student stu2 : stuSet) {System.out.println(stu2);}}
}
执行结果:
Student [name=郭德纲, age=44]
Student [name=于谦, age=43]
Student [name=郭麒麟, age=23]

LinkedHashSet

HashSet 保证元素唯一, 可是元素存放进去是没有顺序的, 我们要保证有序, 怎么办?

HashSet 下有一个子类java.util. LinkedHashSet , 它是链表和哈希表组合的一个数据存储结构

public class LinkedHashSetDemo {public static void main(String[] args) {Set<String> set = new LinkedHashSet<String>();set.add("bbb");set.add("aaa");set.add("abc");set.add("bbc");Iterator<String> it = set.iterator();while (it.hasNext()) {System.out.println(it.next());}}
}
结果:bbbaaaabcbbc
// 与添加的顺序相同

可变参数

我们定义一个方法需要接受多个参数, 并且多个参数类型一致,通常的写法是

修饰符 返回值类型 方法名(参数类型[] 形参名)

其实完全等价于

修饰符 返回值类型 方法名(参数类型...  形参名)

前者在调用时必须传递数组, 后缀直接传递数据; JDK1.5以后 , 出现了 … 用在参数之上,称之为可变参数;

不用创建数组, 直接将数组中的元素作为实际参数进行传递

其实编译成的class文件, 还是将这些元素先封装到一个数组中, 在进行传递; 这些动作都在编译 .class文件时, 自动完成了

public class ChangeArgs{public static void main(String[] args){int[] arr = {1,464,35,429};int sum = getSum(arr);System.out.println(sum)int sum = getSum(1,5,3,8,2,45);System.out.println(sum)/* 自动完成的完成数组 所有元素求和的  原始写法public static void getSum(init[] arr){int sum = 0;for(int a : arr){sum += a;}return sum;}*/// 可变参数写法public static int getSum(int... arr){int sum =0;for(int a:arr){sum += a;}return sum;}}
}

注意 : 这个方法如果拥有多个参数, 参数中包含可变参数, 可变参数一定要在参数列表的末尾位置

5 Collections 类

注意是 Collcetions, 后面有 s ,它是一个集合工具类, 在java.util.Collections, 部分方法如下

  • public static <T> boolean addAll(Collection<T> c,T....elements): 往集合中添加一些元素
  • public static void shuffle(List<?> list) : 打乱集合顺序
  • public static void sort(List<T> list) : 将集合中元素按照默认规则排序
  • public static <T> void sort(List<T> List,Comparator<? super T>) : 将集合中元素按照指定规则排序
import java.util.ArrayList;
import java.util.Collections;public class Dem01Collections {public static void main(String[] args) {ArrayList<Integer> list = new ArrayList<>();Collections.addAll(list,5,36,45,89,252,649,159);System.out.println(list);System.out.println("==================");Collections.shuffle(list);System.out.println(list);System.out.println("==================");Collections.sort(list);System.out.println(list);}
}

Comparator比较器

比较两种对象之间的大小, Java提供了两种比较实现的方式, 一种是死板的采用 java.lang.Comparable , 还有一种句式自定义的灵活的ava.util.Comparator

Collections 自带的 sort() 实现的就是前者,在comparable接口完成比较的功能

public final class String implements java.io.Serializable, Comparable<String>, CharSequence {}

我自定义的比较器 使用 public static <T> void sort(List<T> list,Comparator<? super T> )

比较器具有可比性, 两个比较的对象谁排在前排在后, 比较的方法是

public int compare(String s1,String s2) : 比较两个参数的顺序

重写Comparator 的 compare方法

两个对象比较的结果有三种:大于,等于,小于。

如果要按照升序排序,
则o1 小于o2,返回(负数),相等返回0,01大于02返回(正数)
如果要按照降序排序
则o1 小于o2,返回(正数),相等返回0,01大于02返回(负数)

// 比较两个字符串 , 按照第一位的字符串倒序排列

public class CollectionsDemo3 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<String>();list.add("cba");list.add("aba");list.add("sba");list.add("nba");//排序方法  按照第一个单词的降序Collections.sort(list, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o2.charAt(0) - o1.charAt(0);}});System.out.println(list);}
}

Comparaable与Comparator的区别

Comparable : 强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo()一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象列表(和数组)可以通过Collections.sort(和Arrays.sort)进行自动排序,对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器

Comparator : 强行对某个对象进行整体排序。可以将Comparator 传递给sort方法(如Collections.sort或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用Comparator来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象collection提供排序

// 自定义一个标准的Student类; 重写Comparable的比较方法

public class Student implements Comparable<Student>{@Overridepublic int compareTo(Student o){return this.age - o.age  // 升序}private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

// 测试类

public class Demo {public static void main(String[] args) {// 创建四个学生对象 存储到集合中ArrayList<Student> list = new ArrayList<Student>();list.add(new Student("rose",18));list.add(new Student("jack",16));list.add(new Student("abc",16));list.add(new Student("ace",17));list.add(new Student("mark",16));/*让学生 按照年龄排序 升序*/
//        Collections.sort(list);//要求该list中元素类型  必须实现比较器Comparable接口for (Student student : list) {System.out.println(student);}}
}

拓展

想要独立的自定义规则, 采用Collections.sort(List list,Comparetor c), 自己定义规则

Collections.sort(list, new Comparator<Student>(){@Overridepublic int compare(Student o1,Student 02){return o2.getAge() - o1.getAge()   // 以学生的年龄排序}
});

如果想要更多规则, 想要在年龄相当的情况下,再次排序

Collections.sort(list, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {// 年龄降序int result = o2.getAge()-o1.getAge();//年龄降序if(result==0){//第一个规则判断完了 下一个规则 姓名的首字母 升序result = o1.getName().charAt(0)-o2.getName().charAt(0);}return result;}});

6 Map

概述

像生活中 IP与主机名, 身份证与个人, 系统用户名与系统用户对象, 这种一一对应的关系,就叫做映射; Java专门提供了专门的集合类用来存放这种对象关系的对象 ,即 java.util.Map 接口

CollectionMap 他们的存储数据的形式不同

  • Collection中的集合, 元素时孤立存在的, 向集合中存储元素采用一个个元素的方式存储; 它是单列集合
  • Map 中的集合, 元素是成对存在的(键值对), 每个元素由键与值两部分组成, 通过键找到所对应的值, 它是双列集合

Map常用子类

常用的有HashMap集合, LinkedHashMap集合

  • HashMap : 存储数据采用的哈希表结构, 元素的存取顺序不能保证一致, 由于要保证键的唯一, 不重复, 需要重写键的hashCode方法, equals方法
  • LinkedHashMap : 存储数据采用的哈希表+链表结构; 通过链表结构可以保证元素的存取顺序一致, 通过哈希表结构可以保证键的唯一, 不重复, 需要重写键的hashCode()方法、equals()方法

Map接口中的集合都有两个泛型变量(键与值), 在使用时 , 要为两个泛型变量赋予数据类型; 两个泛型变量的数据类型可以相同, 也可以不同

Map接口中常用的方法

Map接口中定义了很多的方法, 常用的如下:

  • public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中
  • public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除, 并且返回被删除元素的值
  • public get(Object key) : 根据指定的键, 在Map集合中获取对应的值
  • boolean containsKey(Object Key) : 判断集合中是否包含指定的键
  • public Set<K> keySet() : 获取Map集合中所有的键, 存储到Set集合中
  • public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)
public class MapDemo{public static void main(String[] args){// 创建map对象HashMap<String,String> map = new HashMap<String,String>()// 添加元素到集合map.put("黄晓明","杨颖");map.put("文章","马伊琍");map.put("邓超","孙俪");System.out.println(map.remove("邓超"))   // 返回的是对应的key// 通过key查看value的值System.out.println(map.get("黄晓明"))}
}

注意 :

1 若remove指定的键不存在, 则返回的为null

2 若指定的key在集合中已经存在, 则返回值为替换前的key对应的value, 并把键对应的值, 替换称为新的值

Map集合遍历键找值的方式

先取出Map集合中 所有的键添加到一个 Set集合中, 然后for增强循环这个 Set, 得到每个key从而获取每个键

分析步骤:

  1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keyset()
  2. 遍历键的Set集合,得到每一个键。
  3. 根据键,获取键所对应的值。方法提示:get(K key)
public class MapDemo{public static void main(String[] args){// 创建Map集合对象HashMap<String,String> map = new HashMap<String,String>();// 添加元素到集合map.put("黄晓明","杨颖");map.put("文章","马伊琍");map.put("邓超","孙俪");// 获取所有的键Set<String> keys = map.keySet();// 遍历键的集合for(String key : keys){// 键 --> 值String value = map.get(key);System.out.println(key+"对应的值为"+value);}}
}

Entry键值对对象

Map中存放的是两种对象, 一种为key, 一种为value; 他们在Map中是一一对应关系, 这一对对象又称为Map的一个 Entry项, Entry 将键值对的对应关系封装成了对象, 即键值对对象; 这样我们在遍历Map集合时, 就可以从每一个键值对 Entry 对象中获取对应的键与对应的值

Entry 表示一对键和值对象, 也提供了获取对应键和对应值的方法

  • public K getKey() : 获取Entr对象中的键
  • public V getValue() : 获取Entry对象中的值

从Map集合中获取所有Entry对象的方法:

public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合只能怪所有的键值对 对象的集合(Set集合)

Map集合遍历键值对方式

键值对方式 : 通过集合中每个键值对(Entry)对象, 获取键值对(Entry)对象中的键与值

操作步骤与图解:

  1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:entrySet()
  2. 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象
  3. 通过键值对(Entry)对象,获取Entry对象中的键与值。 方法提示:getkey() getValue()

注意 : Map集合不能直接使用迭代器或者 forearch进行遍历; 但是转成Set之后就可以使用了

public class MapDemo02{public static void main(String[] args){// 创建Map集合对象HashMap<String,String> map = new HashMap<String,String>();// 添加元素到集合map.put("胡歌", "霍建华");map.put("郭德纲", "于谦");map.put("薛之谦", "大张伟");// 获取所有的Entry对象Set<Entry<String,String>> entrySet = map.entrySet();// 遍历得到每一个entry对象for(Entry<String,String> entry: entrySet){// 解析 key,valueString key = entry.getKey();String value = entry.getValue();System.out.println(key+"对应的值"+value)}}
}

HashMap存储自定义类型键值

练习 : 每位学生对象有(姓名,年龄) , 现在还有各自的家庭住址(String), 将他们存储到map集合当中

key : Student value : String

// 学生类, 需要重写 hashCode() 和 equals()

public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o)return true;if (o == null || getClass() != o.getClass())return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}

// 测试类

public class HashMapTest{public static void main(String[] args){// 创建HashMap集合对象Map<Student,String> map = new HashMap<Student,String>();// 添加元素map.put(new Student("张三",22),"上海");map.put(new Student("李四",12),"武汉");map.put(new Student("王五",29),"北京");map.put(new Student("赵六",19),"南京");map.put(new Student("孙七",20),"深圳");// 取出元素, 键找值Set<Student,String> keySet = map.keySet()for(Student key:keySet){String value = map.get(key);System.out.println(key.toString()+"他的家庭住址 :"+value)}}
}

LinkHashMap

HashMap保证成对元素唯一, 并且查询速度很快, 但是成对元素放进去是没得顺序的, 那么我们要保证有序, 就得使用LinkedHashMap, 它是一个链表+哈希表组合的一个数据存储结构

public class LinkedHashMapDemo {public static void main(String[] args) {LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();map.put("邓超", "孙俪");map.put("李晨", "范冰冰");map.put("刘德华", "朱丽倩");Set<Entry<String, String>> entrySet = map.entrySet();for (Entry<String, String> entry : entrySet) {System.out.println(entry.getKey() + "  " + entry.getValue());}}
}

练习 : 计算一个字符串中每个字符出现的次数

获取字符串的 字节,存入集合作为键, 次数作为它的key ; 若存在则++

分析:

  1. 获取一个字符串对象来记录输入的字符串
  2. 创建一个Map集合, 键代表字符串中的每个字符, 值代表出现的次数
  3. 遍历字符串得到每一个字符
  4. 判断Map集合中是否有以该字符作为键
  5. 如果没有 , 第一次出现, 存储次数为1; 如果有, 则说明已经出现过, 获取到对应的值++, 再次存储
public class MapTest {public static void main(String[] args) {//友情提示System.out.println("请录入一个字符串:");String line = new Scanner(System.in).nextLine();// 定义 每个字符出现次数的方法findChar(line);}private static void findChar(String line) {//1:创建一个集合 存储  字符 以及其出现的次数HashMap<Character, Integer> map = new HashMap<Character, Integer>();//2:遍历字符串for (int i = 0; i < line.length(); i++) {char c = line.charAt(i);//判断 该字符 是否在键集中if (!map.containsKey(c)) {//说明这个字符没有出现过//那就是第一次map.put(c, 1);} else {//先获取之前的次数Integer count = map.get(c);//count++;//再次存入  更新map.put(c, ++count);}}System.out.println(map);}
}

JDK9对集合添加的优化

在代码中创建一个集合(例如 List或 Set), 并直接使用一些元素填充它, 会调用几个add方法,使得代码重复

在JDK9中, 添加了几种结合工厂方法, 更方便创建少量元素的集合, map示例; 新的List,Set, Map的静态工厂方法可以更方便地创建集合的不可变实例

public class HelloJDK9 {  public static void main(String[] args) {  Set<String> str1=Set.of("a","b","c");  //str1.add("c");这里编译的时候不会错,但是执行的时候会报错,因为是不可变的集合  System.out.println(str1);  Map<String,Integer> str2=Map.of("a",1,"b",2);  System.out.println(str2);  List<String> str3=List.of("a","b");  System.out.println(str3);  }
}

注意 :

1.of() 方法是指Map,Set,List这三个接口的静态方法, 其父类接口和子类并没有这类方法 , 比如HashSet, ArrayList等等;

  1. 返回的集合是不可变类型

7 Debug追踪与调试

可以让代码逐行执行, 查看代码之心搞得过程, 调试程序中出现的bug

  1. 在有效代码行 , 点击行号右边的空白区域, 设置断点, 程序执行到断点将停止, 然后手动运行程序
  2. 点击Debug运行模式
  3. 程序停止在断点上不再执行, 而在IDEA最下方打开Debug调试窗口
  4. F8 逐行执行程序 F7进入到方法中 shift+F8 跳出方法 f9跳到下一个断点
  5. 快捷键F8,代码向下执行一行,第九行执行完毕,执行到第10行(第10行还未执行)
  6. 快捷键F8,程序继续向后执行, …
  7. 查看每一步的运行结果 继续F8
  8. 如果不想继续debug,那么可以使用快捷键F9,程序正常执行到结束,程序结果在控制台显示

8 模拟斗地主案例

分析

具体规则 :

  1. 组装54张扑克牌
  2. 将54张牌打乱
  3. 三个玩家参与游戏, 三人交替摸牌, 每人17张, 最后三张作为底牌
  4. 最后,查看三个手中各自的牌(按牌的大小排序)

需求分析

  1. 准备牌 : 完成数字与纸牌的映射关系, 使用HashMap集合, 完成一个数字与字符串纸牌的对应关系
  2. 洗牌 : 通过数字完成洗牌
  3. 发牌: 将每个人以及底牌设计为ArrayList, 最后三张直接存放于底牌, 剩余的牌通过对 3 取模依次发牌. 存放的过程中要求数字大小与斗地主规则的大小对应, 将不同纸牌的数字分配给不同的玩家与底牌
  4. 看牌 : 通过Map结合找到对应字符展示, 通过查询纸牌与数字的对应关系, 由数字转成纸牌字符串再进行展示

分析图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SD3OgpHS-1589289415703)(assets/1589202689567.png)]

代码步骤

public class Poker {public static void main(String[] args) {/** 1组装54张扑克牌*/// 1.1 创建Map集合存储HashMap<Integer, String> pokerMap = new HashMap<Integer, String>();// 1.2 创建 花色集合 与 数字集合ArrayList<String> colors = new ArrayList<String>();ArrayList<String> numbers = new ArrayList<String>();// 1.3 存储 花色 与数字Collections.addAll(colors, "♦", "♣", "♥", "♠");Collections.addAll(numbers, "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3");// 设置 存储编号变量int count = 1;pokerMap.put(count++, "大王");pokerMap.put(count++, "小王");// 1.4 创建牌 存储到map集合中for (String number : numbers) {for (String color : colors) {String card = color + number;pokerMap.put(count++, card);}}/** 2 将54张牌顺序打乱*/// 取出编号 集合Set<Integer> numberSet = pokerMap.keySet();// 因为要将编号打乱顺序 所以 应该先进行转换到 list集合中ArrayList<Integer> numberList = new ArrayList<Integer>();numberList.addAll(numberSet);// 打乱顺序Collections.shuffle(numberList);// 3 完成三个玩家交替摸牌,每人17张牌,最后三张留作底牌// 3.1 发牌的编号// 创建三个玩家编号集合 和一个 底牌编号集合ArrayList<Integer> noP1 = new ArrayList<Integer>();ArrayList<Integer> noP2 = new ArrayList<Integer>();ArrayList<Integer> noP3 = new ArrayList<Integer>();ArrayList<Integer> dipaiNo = new ArrayList<Integer>();// 3.2发牌的编号for (int i = 0; i < numberList.size(); i++) {// 获取该编号Integer no = numberList.get(i);// 发牌// 留出底牌if (i >= 51) {dipaiNo.add(no);} else {if (i % 3 == 0) {noP1.add(no);} else if (i % 3 == 1) {noP2.add(no);} else {noP3.add(no);}}}// 4 查看三人各自手中的牌(按照牌的大小排序)、底牌// 4.1 对手中编号进行排序Collections.sort(noP1);Collections.sort(noP2);Collections.sort(noP3);Collections.sort(dipaiNo);// 4.2 进行牌面的转换// 创建三个玩家牌面集合 以及底牌牌面集合ArrayList<String> player1 = new ArrayList<String>();ArrayList<String> player2 = new ArrayList<String>();ArrayList<String> player3 = new ArrayList<String>();ArrayList<String> dipai = new ArrayList<String>();// 4.3转换for (Integer i : noP1) {// 4.4 根据编号找到 牌面 pokerMapString card = pokerMap.get(i);// 添加到对应的 牌面集合中player1.add(card);}for (Integer i : noP2) {String card = pokerMap.get(i);player2.add(card);}for (Integer i : noP3) {String card = pokerMap.get(i);player3.add(card);}for (Integer i : dipaiNo) {String card = pokerMap.get(i);dipai.add(card);}//4.5 查看System.out.println("令狐冲:"+player1);System.out.println("石破天:"+player2);System.out.println("鸠摩智:"+player3);System.out.println("底牌:"+dipai);}
}

tring>();
ArrayList player2 = new ArrayList();
ArrayList player3 = new ArrayList();
ArrayList dipai = new ArrayList();
// 4.3转换
for (Integer i : noP1) {
// 4.4 根据编号找到 牌面 pokerMap
String card = pokerMap.get(i);
// 添加到对应的 牌面集合中
player1.add(card);
}
for (Integer i : noP2) {
String card = pokerMap.get(i);
player2.add(card);
}
for (Integer i : noP3) {
String card = pokerMap.get(i);
player3.add(card);
}
for (Integer i : dipaiNo) {
String card = pokerMap.get(i);
dipai.add(card);
}
//4.5 查看
System.out.println(“令狐冲:”+player1);
System.out.println(“石破天:”+player2);
System.out.println(“鸠摩智:”+player3);
System.out.println(“底牌:”+dipai);
}
}


Java数据结构及工具类的详解相关推荐

  1. (二)java生成随机数工具类RandomUtils详解

    /*** 生成一个随机的布尔值*/boolean flag = RandomUtils.nextBoolean();System.out.println(flag);/*** 创建一个bytes随机数 ...

  2. java 日期处理工具类_Java日期处理工具类DateUtils详解

    本文实例为大家分享了Java日期处理工具类DateUtils的具体代码,供大家参考,具体内容如下 import java.sql.Timestamp; import java.text.ParseEx ...

  3. (7)Java数据结构--集合map,set,list详解

    MAP,SET,LIST,等JAVA中集合解析(了解) - clam_clam的专栏 - CSDN博---有颜色, http://blog.csdn.net/clam_clam/article/det ...

  4. JAVA高效率 (秒级) 将千万条数据导入数据库 (已封装工具类)【详解】【一看就懂】

    该gif做了加速处理,便于观看~  今天在将一个500w+条数据的文件导入至数据库时,遇到一个异常,相信做大数据应该都有遇到.500w条数据说多不多,说少也不少.既然问题出现了,那么就一定要解决. 异 ...

  5. (五)Java工具类ArrayUtils详解

    说明:ArrayUtils工具类在标准的应用程序中是不可以被实例化的:  参考:[参考地址](http://commons.apache.org/proper/commons-lang/javadoc ...

  6. java 加减乘除 工具类_Java数学工具类MathUtil详解

    package cn.xbz.util.math; import java.math.BigDecimal; /** * @title 数学计算工具类 * @description 提供常用的数值加减 ...

  7. java json 工具类_Java中JSON处理工具类使用详解

    本文实例为大家分享了JSON处理工具类的具体代码,供大家参考,具体内容如下 import java.io.IOException; import java.util.Date; import java ...

  8. Java并发工具类--CyclicBarrier详解

    CyclicBarrier允许一组线程在到达某个栅栏点(common barrier point)互相等待,直到最后一个线程到达栅栏点,栅栏才会打开,处于阻塞状态的线程恢复继续执行. 举例 举个例子来 ...

  9. Java中的StringBuilder类功能详解

    字符串是Java程序中最常用的一种数据结构之一.在Java中的String类已经重载的"+".也就是说,字符串可以直接使用"+"进行连接,如下面代码所示: St ...

最新文章

  1. Elasticsearch简史:源自给老婆开发烹饪App
  2. 女程序猿2014总结(修改)
  3. Windows下Mysql Cluster集群启动脚本与启动服务添加方法
  4. eclipse导入github项目
  5. Vue页面骨架屏(一)
  6. 前端学习(2586):如何设计高扩展路由
  7. 开源目标检测算法用于交通标志检测全方位评估
  8. 最重要的 Java EE 最佳实践
  9. socket编程(九)
  10. vmVare使用NAT模式-配置详情
  11. zlib再windows下的编译
  12. python实现五子棋游戏(控制台版)
  13. intptr_t 和 uintptr_t类型使用总结
  14. Word操作技巧大全
  15. c语言windows文本框,windows编程 如何创建文本框?
  16. python行星名称输出_用python绘制行星轨道
  17. python自动化交易 期货_一只股票一天可以撤单单几次
  18. 计算机基础知识---位运算的应用
  19. enumerate()
  20. 关于babe-loader^8.0.6的配置问题

热门文章

  1. ROS1和ROS2RVIZ 代码详解
  2. Autosar XCP在INCA中的使用
  3. datagrip 导出 Oracle 数据库结构和数据到sql脚本中
  4. 信息安全体系建设☞开源入侵检测系统NIDS
  5. 码农福利,自定义微博小尾巴,闪瞎他们的双眼
  6. A-LOAM构建3d点云地图并实时转存二维栅格地图
  7. 谣言!华为官方回应停止社会招聘
  8. 昆仑通态与西门子1200
  9. 【FXCG】对市场保持敬畏之心
  10. php中文网 老板,thinkphp问答系统后台老板的列表展示