第一节
一、集合框架的学习方式
1、学习顶层:
学习顶层接口/抽象类中共性的方法,所有的子类都可以使用
2、使用底层:
底层不是接口就是抽象类,无法创建对象使用,需要使用底层的子类创建对象使用
Collection接口
定义的是所有单列集合中共性的方法
所有的单列集合都可以使用共性的方法
没有带索引的方法
List接口
(是单列集合的一种)
1、有序的集合(存储和取出元素顺序相同)
2、允许存储重复的元素
3、有索引,可以使用普通的for循环遍历
List接口中有以下子类:ArrayList(重点) LinkedList(次之) Vector(了解)
ArrayList:底层是数组实现的,查询快,增删慢
LinkedList:底层是链表实现的,查询慢,增删快
Set接口
(是单列集合的一种)
1、不允许存储重复的元素、存取无序
2、没有索引(不能使用普通的for循环遍历)
Set接口中有一下子类:HashSet(重点) LinkedHashSet(次之) TreeSet(了解)
HashSet:底层是哈希表+(红黑树)实现的,无索引、不可以存储重复元素,存取无序
LinkedHashSet:底层是哈希表+链表实现的,无索引,不可以存储重复元素,可以保证存取顺序
TreeSet:底层是二叉树实现。一般用于排序
二、Iterator迭代器
java.util.Iterator接口:迭代器(对集合进行遍历)
有两个常用的方法
boolean hasNext() 如果仍有元素可以迭代,则返回true。(判断集合中还有没有下一个元素,有就返回true,没有就返回false)
E next() 返回迭代的下一个元素。(取出集合中下一个元素)
Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊。Collection接口中有一个方法叫iterator(),这个方法返回的就是迭代器的实现类对象
Iterator iterator() 返回在此collection的元素上进行迭代的迭代器
迭代器的使用步骤:
1、使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
2、使用iterator接口中的方法hasNext判断还有没有下一个元素
3、使用iterator接口中的方法next取出集合中的下一个元素
增强for循环
增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合,它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作
格式
for(元素的数据类型 变量名 :Collection集合名or数组名){
//写操作代码
sout(变量名);
}
三、泛型
泛型:是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型
泛型也可以看成是一个变量,用来接收数据类型
E e:Element 元素
T t:Type 类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mexAZx8R-1615820935369)(D:\Program Files\java笔记\Java自我小结\linux\泛型.PNG)]
定义含有泛型的类
定义格式:
修饰符 class 类名<代表泛型的变量泛型>{ }
定义含有泛型的方法
定义格式:
修饰符 <代表泛型的变量> 返回值类型 方法名称(参数){ }
定义含有泛型的接口
定义格式:
修饰符 interface 接口名<代表泛型的变量>{ }
含有泛型的接口,第一种方式:定义接口的实现类,实现接口,指定接口的泛型
public class GenericInterfaceImpl implements GenericInterface{
@Override
…
}
含有泛型的接口,第二种方式:接口时是什么泛型实现类就是什么泛型,类跟着接口走。就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型
public class GenericInterfaceImpl implements GenericInterface {
@Override
…
}
泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用
通配符基本使用
泛型的通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
此时只能接收数据(只能作为方法的参数传递),不能往该集合中存储数据
详细代码见:D:\Learn\javaAgain\src\year21Month01\Month01Day12\GenericClass\GenericDemo02.class 文件
泛型的上限限定和下限限定
泛型的上限限定:? extends E 代表使用的泛型只能是E类型的子类/本身
泛型的上限限定:? super E 代表使用的泛型只能是E类型的父类/本身
集合综合案例
斗地主案例:
package year21Month01.Other.斗地主案例;
import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Collectors;
/**
* @Author:pp
* @Date:2021/1/16 16:00
*/
public class DouDiZhu {
public static void main(String[] args) {
//1、准备排
//1.1首先准备一个集合用来存储54张牌
ArrayList<String> poker = new ArrayList<>();
//2、准备两个集合分别用来存储花色和序号
String [] color = {"♥","♣","♦","♠"};
String [] number = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
//3、将大王小王放入poker中
poker.add("大王");
poker.add("小王");
//4、将花色和序号匹配,用一个嵌套for循环,并将匹配好的放入集合poker中
for (String c:color) {
for (String n:number){
poker.add(c+n);
}
}
//5、洗牌
//5.1运用collections中的shuffle方法。
Collections.shuffle(poker);
System.out.println(poker);
//6、发牌
//6.1首先要准备四个集合,分别用来存放玩家的牌和剩余的三张底牌
ArrayList<String> play01 = new ArrayList<>();
ArrayList<String> play02 = new ArrayList<>();
ArrayList<String> play03 = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
//6.2首先将扑克中的牌取出来,再进行分发
for (int i = 0; i < poker.size(); i++) {
String p = poker.get(i);
//进行判断底牌的分发,如果不先进行底牌分发。直接进行玩家分发,到时候是没有底牌的
if (i>=51){
dipai.add(p);
}else if (i%3==0){
play01.add(p);
}
else if (i%3==1){
play02.add(p);
}
else if (i%3==2){
play03.add(p);
}
}
//7、看牌
System.out.println("玩家01:"+play01);
System.out.println("玩家02:"+play02);
System.out.println("玩家03:"+play03);
System.out.println("底牌:"+dipai);
}
}
第二节
一、常见的数据结构
数据存储的常用结构有:栈、队列、数组、链表和红黑树
栈
·栈:Stack,又称为栈它是运算受限的线性表,其限制是仅允许在表的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作
简单的说:采用该结构的集合,对元素的存取有如下的特点:
1、先进后出(即,存进去的元素,要在它后面的元素依次取出后,才能取出该元素)。例如,子弹压进弹夹,先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能取出下面的子弹
2、栈的入口、出口都是栈的顶端位置
队列
·队列:queue,简称队,它同栈一样,也是一种运算受限的线性表,其限制是允许在表的一端进行插入,而在表的另一端进行删除
简单的说:采用该结构的集合,对元素的存取有如下特点:
1、先进先出(即,存进去的元素要在它前面的元素依次取出后,才能取出该元素)。例如,小火车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来
2、队列的入口、出口各占一侧
数组
·数组:Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人。
简单的说:采用该结构的集合,对元素的存取有如下的特点:
1、查找速度快:通过索引,可以快速访问指定位置的元素
2、增删元素慢
指定索引位置增加元素:需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。
链表
·链表 :linked list,由一系列节点node(链表中每一个元素称为节点),节点在运行时可以动态生成,每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。我们常说的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o98YDIOF-1615820935372)(D:\Program Files\java笔记\Java自我小结\linux\单向链表.PNG)]
简单的说,采用该结构的集合,对元素的存取有如下的特点:
1、多个节点之间,通过地址进行链接。例如,多个人手拉手,每个人使用自己的右手拉住下一个人的左手,依次类推,这样多个人就连在一起了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n66hu9Bq-1615820935373)(D:\Program Files\java笔记\Java自我小结\linux\单向链表1.PNG)]
2、查找元素慢:想查找某个元素,需要通过连接的节点,一次向后查找指定元素(每次查询都必须从头开始查询)
3、增删元素快
·增加元素:只需要修改连接下个元素的地址即可
单向链表:链表中只有一条链子,不能保证元素的顺序(存储元素和取出元素的顺序有可能不一致)
双向链表:链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合
红黑树
(特点:趋近于平衡树,查询的速度非常快,查询叶子节点最大次数和最小次数不能超过2倍)
·二叉树:binary tree,是每个节点不超过2的有序树(tree)
简单的理解:就是一种类似于我们生活中树的结构,只不过每个节点上都最多只能有两个子节点。
二叉树是每个节点最多有两个子树的结构,顶上的叫根节点,两边被称作“左子树”和“右子树”
·查找树/排序树
在二叉树的基础上,元素是有大小顺序的
左子树小,右子树大
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BI7Fwj54-1615820935375)(D:\Program Files\java笔记\Java自我小结\linux\排序树.PNG)]
第三节 List集合
一、List接口介绍
java.util.List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。在List集合中允许出现重复的元素,所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素。另外,List集合还有一个特点就是元素有序,即元素的存入顺序和取出顺序一致。
List接口的特点:
1、它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的。
2、它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)
3、集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素
二、ArrayList集合
java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合
三、LinkedList集合
java.util.LinkedList集合数据存储的结构是链表结构。方便元素增加、删除的集合
LinkedList是一个双向链表(实际开发中对一个集合元素的添加与删除经常涉及到首位操作)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L4EjQQOL-1615820935377)(D:\Program Files\java笔记\Java自我小结\linux\LinkedList.PNG)]
第四节 Set接口
一、HashSet集合介绍
java.util.Set接口和java.util.List接口一样,同样继承自Collection接口,它与Collection接口中的方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection接口更加严格。与List接口不同的是,Set接口中元素无序,并且都会以某种规则保证存入的元素不重复。
Set集合有多个子类,这里我们介绍其中的java.util.HashSet、java.util.LinkedHashSet这两个集合。
注释:Set集合取出元素的方式可以采用:迭代器、增强for。
java.util.HashSet是Set接口的一个实现类,它所存储的元素是不可重复的,并且元素都是无序的(即存取顺序不一致)。java.util.HashSet底层的实现其实是一个java.util.HashMap支持,
HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因为具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode与equals方法
二、HashSet集合存储数据的结构(哈希表)
什么是哈希表?
在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查询时间。
简单的说,哈希表是由数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的
set集合存储元素不重复的元素(例,存储自定义类型的元素:Person、Student)
前提:存储的元素必须重写hashCode方法和equals方法。比较方式:首先比较hashCode值是否相同,不同则在对应数组中hashCode值中存储元素。若相同,再比较equals方法,若相同则不进行存储,若不同则在对应数组中hashCode值中存储元素
三、LinkedHashSet集合
/**
* java.util.LinkedHashSet集合 extends HashSet集合
* LinkedHashSet集合的特点:
* 底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序)
* 保证元素有序
*/
四、可变参数
/**
VarArgs可变参数 (数据类型...变量名)
可变参数是JDK1.5以后出现的新特性
使用前提:
当方法的参数列表数据类型已经确定,但是参数个数不确定,就可以使用可变参数
使用格式:
修饰符 返回值类型 方法名(数据类型...变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
传递的参数可以是0个(不传递)或多个
* */
public class Demo04VarArgs {
public static void main(String[] args) {
int result = add(10, 20);
System.out.println(result);
}
/*
可变参数的注意事项:
1、一个方法的参数列表,只能有一个可变参数 (错误写法:int...a,double...c)
2、如果方法的参数列表有多个,那么可变参数必须写在参数列表的末尾(int a,double b,int...c)
*/
//可变参数的特殊(终极)写法
public static void method(Object...obj){}
/**
* 定义一个方法,计算(0-n)整数的和
* 已知:计算的是和,数据类型已经确定,但是传递的参数不确定,则可以使用可变参数
*/
private static int add(int...arr) {
int sum = 0 ;
for (int i:arr) {
sum+=i;
}
return sum;
}
}
第五节 Collections
一、常用方法介绍
java.util.Collections是集合工具类,用来对集合进行操作
·public static boolean addAll(Collection c,T…elements):往集合中添加一些元素
·public static void shuffle(List<?> list)打乱顺序:打扰集合顺序
·public static void sort(List list):将集合中元素按照默认规则排序
.public static void sort(List list,Comparator <? super T):将集合中元素按照指定规则排序
public class Demo01Collections {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"a","b","c","d","e");
// System.out.println(list);
// Collections.shuffle(list);
// Collections.sort(list);
/**
* -java.util.Collections是集合工具类,用来对集合进行操作。部分方法如下:
* public static <T> void sort(List<T> list):将集合中元素按照默认规则排序
*
* 注意:
* sort(List<T> list)使用前提:
* 被排序的集合里边存储的元素,必须实现comparable接口,重写接口中的方法compareTo定义排序规则
Comparable接口的排序规则:
自己(this)-参数:升序
*/
ArrayList<Person> list01 = new ArrayList<>();
list01.add(new Person("张三",20));
list01.add(new Person("李四",16));
list01.add(new Person("王五",13));
System.out.println(list01);
Collections.sort(list01);
System.out.println(list01);
//作为扩展:了解
ArrayList<Student> list02 = new ArrayList<>();
Student s1 = new Student("b迪丽热巴",18);
Student s2 = new Student("古力娜扎",20);
Student s3 = new Student("马儿扎哈",13);
Student s4 = new Student("a迪丽热巴",18);
list02.add(s1);
list02.add(s2);
list02.add(s3);
list02.add(s4);
System.out.println(list02);
Collections.sort(list02, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序
int result = o1.getAge()-o2.getAge();
//如果年龄相同,再使用姓名第一个字进行比较
if (result==0){
result = o1.getName().charAt(0)-o2.getName().charAt(0);
}
return result;
}
});
System.out.println(list02);
}
}
sort两种比较方法:
1、类实现Comparable接口,重写CompareTo方法
2、主函数中调用Collections.sort方法,new Comparator<T>(){}
第六节 Map集合
一、概述
现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号和个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Maps接口
·Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储
·Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键和值两部分组成,通过键可以找所对应的值
·Collection中的集合称为单列集合,Map中的集合称为双列集合。
·需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值
二、Map集合的特点
1、Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
2、Map集合中的元素,key和value的数据类型可以相同,可以不同
3、Map集合中的元素,key是不允许重复的,value是可以重复的
4、Map集合中的元素,key和value是一一对应的
三、Map常用子类
主要讲解常用的HashMap集合、LinkedHashMap集合
·HashMap<K,V>:存储数据采用的是哈希表结构(查询速度非常快-数组+单向列表/红黑树(阈值>8)),元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法
java.util.hashMap<K,V>集合 implements Map<K,V>接口
HashMap是一个无序的集合,存储元素和取出元素的顺序有可能不一致
·LinkedHashMap<K,V>:HashMap下有一个子类LinkedHashMap,存储数据采用的是哈希表结构+链表结构(保证迭代的顺序)。通过链表结构可以保证元素的存取顺序一致;通过哈希结构可以保证键的唯一、不重复,需要写键的hashCode()方法、equals()方法
LinkedHashMap集合是一个有序的集合,存储和取出元素的顺序是一致的
tips:Map接口中的集合有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋值数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同
四、Map接口中的常用方法
·public V put (K key,V value):把指定的键与指定的值添加到Map集合中
·public V remove(Object key):把指定的键所对应的键值对元素在Map集合中删除,返回被删除元素的值
·public V get(Object key):根据指定的键,在Map集合中获取对应的值
·boolean containsKey(Object key):判断集合中是否包含指定的键
·public Set keySet():获取Map集合中所有的键,存储到Set集合中
·public Set<Map.Entry<K,V>> extrySet():获取到Map集合中所有的键值对对象的集合(Set集合)
public class Demo01Map {
public static void main(String[] args) {
show04();
}
/**
* boolean containsKey(Object key):判断集合中是否包含指定的键
* 包含返回true 不包含返回false
*/
private static void show04() {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
//向集合中添加元素
map.put("李前",18);
map.put("田磊",18);
map.put("陈恒宇",18);
map.put("谢春雨",18);
// 判断集合中是否包含指定的键
boolean b1 = map.containsKey("田磊");
System.out.println(b1);
}
/**
* public V get(Object key):根据指定的键,在Map集合中获取对应的值
* 返回值v:
* key值存在,v返回获取到的值
* key值不存在,v返回null
*/
private static void show03() {
//创建Map集合对下不过
Map<Integer,String> map = new HashMap<>();
//向集合中添加元素
map.put(2410,"田磊");
map.put(2411,"谢春雨");
map.put(2412,"陈恒宇");
map.put(2413,"李前");
System.out.println(map);
//通过指定的键来获取对应的值
String v1 = map.get(2410);
//田磊
System.out.println(v1);
String v2 = map.get(2416);
//null
System.out.println(v2);
}
/**
* public V remove(Object key):
* 把指定的键所对应的键值对元素在Map集合中删除,返回被删除元素的值
* 返回值V:
* key存在,v返回被删除的值
* key不存在,v返回null
*/
private static void show02() {
//创建Map集合对象
Map<String,Integer> map = new HashMap<>();
//向集合中添加元素
map.put("李前",168);
map.put("田磊",169);
map.put("谢春雨",175);
System.out.println(map);
//通过指定的键删除在Map集合中对应的键值对
Integer v1 = map.remove("李前");
System.out.println(v1);
Integer v2 = map.remove("李前");
System.out.println(v2);
System.out.println(map);
}
/**
* //public V put (K key,V value):把指定的键与指定的值添加到Map集合中
* 返回值V:
* 存储键值对的时候,key不重复,V值返回的是null
* 存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值
*/
private static void show01() {
//创建Map集合对象,多态
Map<String,String> map = new HashMap<>();
String p1 = map.put("张三", "张是");
System.out.println(p1);
String p2 = map.put("张三", "张v");
// System.out.println(p2);
map.put("2410","李前");
map.put("2411","田磊");
map.put("2412","田磊");
System.out.println(map);
}
}
五、Map集合遍历键找值方式
键找值方式:即通过元素中的键,获取键所对应的值
分析步骤:
1、获取Map集合中所有的键,由于键是唯一的所以返回一个Set(不允许存储重复的元素)集合存储所有的键。方法提示:keySet()
2、遍历键的Set集合,得到每一个键
3、根据键,获取键所对应的值。方法提示:get(K key)
代码演示:
public class Demo02KeySet {
public static void main(String[] args) {
//创建Map集合对象,多态
Map<String,Integer> map = new HashMap<>();
//向集合中添加元素
map.put("田磊",168);
map.put("李前",158);
map.put("写春雨",178);
//1、使用Map集合中的keySet()方法,把Map集合中所有的key取出来,存放到set集合中
Set<String> set = map.keySet();
//当然也可以获取迭代器的方法
Iterator<String> it = set.iterator();
while (it.hasNext()){
String key = it.next();
//3、通过调用Map集合的get(Object key)方法,通过key找到value
Integer values = map.get(key);
System.out.println(key+"="+values);
}
System.out.println("================================");
//2、遍历set集合,获取Map集合中所有的key
for (String key:set) {
//3、通过调用Map集合的get(Object key)方法,通过key找到value
Integer values = map.get(key);
System.out.println(key+"="+values);
}
}
}
六、Entry键值对对象
我们已经知道,Map集合中存放的是两种对象,一种称为key(键),一种称为value(值),它们在Map集合中是一一对应的关系,这一对对象又称做Map中的一个Entry(项)。Entry将键值对的对应关系封装成了对象。即键值对对象,这样我们在遍历Map集合时,就可以从每一个键值对(Entry)对象中获取对应的键与对应的值。
既然Entry表示了一对键和值,那么也同样提供了获取对应键和对应值的方法:
·public K getKey():获取Entry对象中的键
·public V getValue():获取Entry对象中的值
七、Map集合遍历键值对方式
Map.Entry<K,V>:在Map接口中有一个内部接口Entry
作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象,用来记录键与值(键值对对象,键与值的映射关系)—>结婚证
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iCf3mEIG-1615820935378)(D:\Program Files\java笔记\Java自我小结\linux\Entry.PNG)]
代码演示:
/**
* Map集合遍历的第二种方式:使用Entry对象遍历
* Map集合中的方法:
* Set<Map.Entry<K,V>> entrySet()返回此映射中包含的映射关系的 Set 视图。
*实现步骤:
* 1、使用Map集合中的entrySet()方法,把Map集合中的多个Entry对象存储到一个set集合中
* 2、遍历set集合,获取Entry对象
* 3、使用Entry对象的getKey()和getValue()方法,获取键与值
*/
public class Demo03EntrySet {
public static void main(String[] args) {
//创建Map集合对象,多态
Map<String,Integer> map = new HashMap<>();
//向集合中添加元素
map.put("田磊",168);
map.put("李前",158);
map.put("写春雨",178);
//1、使用Map集合中的entrySet()方法,把Map集合中的多个Entry对象存储到一个set集合中
Set<Map.Entry<String, Integer>> set = map.entrySet();
//2、遍历set集合,获取Entry对象
//使用迭代器遍历
Iterator<Map.Entry<String, Integer>> it = set.iterator();
while (it.hasNext()){
Map.Entry<String, Integer> entry = it.next();
//3、使用Entry对象的getKey()和getValue()方法,获取键与值
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
System.out.println("==============================");
//使用增强for循环遍历
for (Map.Entry<String,Integer> entry: set){
String key = entry.getKey();
Integer value = entry.getValue();
System.out.println(key+"="+value);
}
}
}
八、HashMap存储自定义类型键值
代码演示:
/**
* HashMap存储自定义类型键值
* Map集合保证key是唯一的:
* 作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
*/
public class HashMapSavePerson {
public static void main(String[] args) {
show02();
}
/**
* HashMap存储自定义类型键值
* key:Person类型
* Person类必须重写hashCode方法和equals方法,才可以保证唯一性
* value:String类型
* value可以重复(同名同年龄视为同一个人)
*
*/
private static void show02() {
//创建HashMap集合
HashMap<Person,String> map = new HashMap<>();
//向集合中添加元素
map.put(new Person("田磊",18),"2410");
map.put(new Person("李前",19),"2410");
map.put(new Person("谢春雨",18),"2410");
map.put(new Person("田磊",18),"2410");
//使用Map集合的entrySet方法和增强for循环遍历集合
Set<Map.Entry<Person, String>> set = map.entrySet();
for (Map.Entry<Person, String> entry : set) {
Person key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"----->"+value);
}
}
/**
* HashMap存储自定义类型键值
* key:String类型
* String类型重写了hashCode方法和equals方法,可以保证唯一性
* value:person类型
* value可以重复(同名同年龄视为同一个人)
*/
private static void show01() {
//创建一个HashMap集合
HashMap<String, Person> map = new HashMap<>();
map.put("北京",new Person("田磊",18));
map.put("上海",new Person("谢春雨",19));
map.put("广州",new Person("李前",20));
map.put("北京",new Person("田磊",18));
//是使用keySet方法和增强for循环遍历集合
Set<String> set = map.keySet();
for (String key : set) {
Person value = map.get(key);
System.out.println(key+"----->"+value);
}
}
}
九、LinkedHashMap
java.util.LinkedHashMap<K,V> extends HashMap<K,V>
Map接口的哈希表和链接列表实现的,具有可预知的迭代顺序
底层原理:
哈希表+链表(记录元素顺序)
十、HashTable
/**
* java.util.hashTable<K,V> implements Map<K,V>
* HashTable:底层也是哈希表,是一个线程安全的集合,是单线程集合,速度慢
* HashMap:底层是哈希表,是一个线程不安全的集合,是多线程集合,速度快
*
* HashMap集合(之前学的所有集合):可以存储null值和null键
* HashTable集合不能存储null值和null键
*
* HashTable和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap和ArrayList)取代了
* HashTable的子类Properties依然活跃在历史舞台
* Properties集合是一个唯一和IO流相结合的集合
*/
十一、集合练习
代码演示:
/**
* 练习:计算一个字符串中每个字符出现的次数
*
* 分析:
* 1、使用Scaner获取用户输入的字符串
* 2、创建Map集合,key是字符串中的字符,value是字符出现的个数
* 3、遍历字符串,获取每一个字符
* 4、使用获取到的字符,去Map集合判断key是否存在
* key存在
* 通过字符(key),获取value(字符个数)
* value++
* put(key,value)把新的value存储到Map集合中
* key不存在
* put(key,1)
*5、遍历Map集合,输出结果
*/
public class Test01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入字符串:");
String str = sc.next();
HashMap<Character,Integer> map = new HashMap<>();
for (char key : str.toCharArray()) {
if (map.containsKey(key)){
Integer value = map.get(key);
value++;
map.put(key,value);
}else {
map.put(key,1);
}
}
Set<Character> set = map.keySet();
for (Character key : set) {
Integer value = map.get(key);
System.out.println(key+"----->"+value);
}
}
}
第七节 知识点补充
一、Debug追踪
使用idea的断点调式功能,查看程序的运行过程
Debug调式程序:
可以让代码逐行执行,查看代码执行的过程,调式程序中出现的bug
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处
执行程序(控制台中也可看到):
f8:逐行执行程序
f7:进入到方法中
shift+f8:跳出方法
f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
ctrl+f2:退出debug模式,停止程序
Console:切换到控制台
第八节 模拟斗地主洗牌发牌
代码演示:
/**
* 斗地主综合案例:有序版本
* 1、准备牌
* 2、洗牌
* 3、发牌
* 4、排序
* 5、看牌
*/
public class DouDiZhu {
public static void main(String[] args) {
//1、准备牌
//创建一个Map集合,存储牌的索引和组装好的牌
HashMap<Integer,String> poker = new HashMap<>();
//创建一个list集合,存储牌的索引
ArrayList<Integer> pokerIndex = new ArrayList<>();
//定义两个集合分别存储牌的花色和牌的序号
ArrayList<String> colors = new ArrayList<>();
ArrayList<String> numbers = new ArrayList<>();
//将牌的花色和牌的序号添加到集合中
Collections.addAll(colors,"♥","♠","♦","♣");
Collections.addAll(numbers,"2","A","K","Q","J","10",
"9","8","7","6","5","4","3");
//把大王小王存放到集合中
//定义一个牌的索引
int index = 0;
poker.put(index,"大王");
pokerIndex.add(index);
index++;
poker.put(index,"小王");
pokerIndex.add(index);
index++;
//循环嵌套遍历两个集合,组装52张牌,存储到集合中
for (String number:numbers){
for (String color:colors){
poker.put(index,color+number);
pokerIndex.add(index);
index++;
}
}
//2、洗牌
//使用Collections中的shuffle方法
Collections.shuffle(pokerIndex);
//3、发牌
//定义4个集合,存储玩家牌的索引和底牌的索引
ArrayList<Integer> play01 = new ArrayList<>();
ArrayList<Integer> play02 = new ArrayList<>();
ArrayList<Integer> play03 = new ArrayList<>();
ArrayList<Integer> diPai = new ArrayList<>();
//遍历存储牌索引的List集合,获取每一个牌的索引
for (int i = 0; i < pokerIndex.size(); i++) {
Integer in = pokerIndex.get(i);
//先判断底牌
if (i>=51){
diPai.add(in);
}
else if (i%3==0){
play01.add(in);
}
else if (i%3==1){
play02.add(in);
}
else if (i%3==2){
play03.add(in);
}
}
/**
* 4、排序
* 使用Collection中的方法sort(list)
* 默认是升序排序
*/
Collections.sort(play01);
Collections.sort(play02);
Collections.sort(play03);
Collections.sort(diPai);
//看牌
//调用看牌的方法
lookPoker("田磊",poker,play01);
lookPoker("李前",poker,play02);
lookPoker("谢春雨",poker,play03);
lookPoker("底牌",poker,diPai);
}
/**
* 定义一个看牌的方法,提高代码的复用性
* 参数:
* String name:玩家名称
* HashMap<Integer,String> poker:存储牌的集合
* ArrayList<Integer> list:存储玩家和底牌的List集合
*
* 查表法:
* 遍历玩家或底牌集合,获取牌的索引
* 使用牌的索引去Map集合中找对应的牌
*/
public static void lookPoker(String name,HashMap<Integer,String> poker,ArrayList<Integer> list){
//输出玩家名称,不换行
System.out.print(name+": ");
//遍历玩家或底牌集合,获取牌的索引
for (Integer key:list){
//使用牌的索引去Map集合中找对应的牌
String value = poker.get(key);
System.out.print(value+" ");
}
//打印完每一个玩家的牌,然后换行
System.out.println();
}
}
更详细代码见:
D:\Learn\javaAgain\src\year21Month01\Other\斗地主案例02\exercese01.java