01、Iterator迭代器
目标:学习使用迭代器获取集合中的数据
讲解:
1.为什么要迭代器:
List接口有索引,我们可以通过for循环+get方法来获取数据,但是Set接口这边没有索引,不能通过for循环 +get方式获取数据.
Collection接口就搞了一种通用的方式方便所有的集合来获取数据,就是迭代器(Iterator)
2.什么是迭代:(过程)
迭代是取数据的过程.先判断集合中是否有数据,如果有,就取出一个数据,接着再判断集合中是否有数据,
如果有再接着取出一个数据,这样往复循环直到所有数据都取出来了.
3.迭代器的常用方法:
interface Iterator {
boolean hasNext() 判断是否有下一个元素,如果有返回true
E next() 返回下一个元素
}
4.迭代器和集合的关系:
Collection接口中有一个方法可以得到迭代器
interface Collection {
Iterator iterator() 返回此集合中元素的迭代器
}
interface List extends Collection {
}
class ArrayList implements List {
pulic Iterator iterator() {
return new 迭代器();
}
}
每个集合都会实现iterator方法,都能获取到迭代器
5.如何获取迭代器:(重点)
集合.iterator();
小结:
1.迭代器的使用步骤?
1.得到迭代器 Iterator itr = list.iterator();
2.循环判断是否有下一个 while (itr.hasNext()) { }
3.如果有,就取出下一个 itr.next()
小贴士:
- 在进行集合元素获取时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会抛出
java.util.NoSuchElementException没有集合元素异常。 - 在进行集合元素获取时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出
ConcurrentModificationException并发修改异常
课堂代码:
import java.util.ArrayList;
import java.util.Iterator;
public class Demo01 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("马蓉");
list.add("李小璐");
list.add("白百合");
list.add("张柏芝");
// 使用迭代器来获取集合的元素
// 1.得到迭代器
// Iterator<String> itr = list.iterator();
// 获取元素
// System.out.println(itr.next());
// System.out.println(itr.next());
// System.out.println(itr.next());
// System.out.println(itr.next());
// System.out.println(itr.next()); // NoSuchElementException: 没有元素异常
// 先判断,再取出
// if (itr.hasNext()) {
// System.out.println(itr.next());
// }
//
// if (itr.hasNext()) {
// System.out.println(itr.next());
// }
//
// if (itr.hasNext()) {
// System.out.println(itr.next());
// }
//
// if (itr.hasNext()) {
// System.out.println(itr.next());
// }
//
// if (itr.hasNext()) {
// System.out.println(itr.next());
// }
// 以上代码都是重复代码, 我们可以改成循环
// 1.得到迭代器
Iterator<String> itr = list.iterator();
// 2.循环判断是否有下一个元素
while (itr.hasNext()) {
// 3.如果有,就取出下一个元素
System.out.println(itr.next());
}
}
private static void test01() {
ArrayList<Integer> list = new ArrayList<>();
list.add(110);
list.add(119);
list.add(120);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i)); // 根据索引去获取数据
}
}
}
02、迭代器的实现原理
目标:理解迭代器的实现原理
讲解:
我们在之前案例已经完成了Iterator遍历集合的整个过程。当遍历集合时,首先通过调用t集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素出,否则说明已到达了集合末尾,停止遍历元素。
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素,为了让初学者能更好地理解迭代器的工作原理
[外链图片转存失败(img-r6yszUt5-1563546017461)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563447472219.png)]
迭代器迭代注意事项:
一次hasNext判断,我们就取一次数据
小结:
1.Iterator的hasNext()作用?
判断是否有下一个元素,如果有返回true
2.Iterator的next()作用?
1.取出下一个元素
2.将指针移动到下一个位置
课堂代码:
import java.util.ArrayList;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("马蓉");
list.add("李小璐");
list.add("白百合");
list.add("张柏芝");
list.add("阿娇");
// "马蓉", "李小璐", "白百合", "张柏芝", "阿娇"
// ↑
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
System.out.println("next1" + itr.next()); // next1马蓉 next1白百合 next1阿娇
// System.out.println("next2" + itr.next()); // next2李小璐 next2张柏芝
}
}
}
03、增强for循环
目标:学习增强for循环和增强for循环的底层
讲解:
1.什么是增强for循环:
JDK1.5推出的新特性.foreach循环,高级for循环
2.增强for格式:
for (数据类型 变量名 : 数组或集合) {
}
3.增强for好处:
代码简单
4.增强for缺点:
没有索引
5.什么时候使用增强for?
如果不关心索引就可以使用增强for
小结:
1.增强for循环格式?
for (元素的类型 变量名 : 数组或集合) {
}
2.增强for循环好处?
代码简单
小结:
增强for循环的底层
1.遍历数组,底层是普通for
2.遍历集合,底层是迭代器
课堂代码:
import java.util.ArrayList;
public class Demo03 {
public static void main(String[] args) {
int[] arr = new int[] {11, 22, 33};
// 使用增强for遍历数组,底层是普通for循环
for (int num : arr) {
System.out.println(num);
}
System.out.println("------------");
ArrayList<Integer> list = new ArrayList<>();
list.add(110);
list.add(119);
list.add(120);
// 使用增强for遍历集合,底层使用的是迭代器
for (Integer num : list) {
System.out.println(num);
}
// 增强for快捷键: 数组或集合.for
}
private static void test01() {
ArrayList<Integer> list = new ArrayList<>();
list.add(110);
list.add(119);
list.add(120);
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i)); // 根据索引去获取数据
}
}
private static void test02() {
int[] arr = new int[] {11, 22, 33};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]); // 根据索引去获取数据
}
}
}
04、斗地主案例
斗地主案例步骤:
1.创建一副牌
1.定义牌类
2.创建集合,用于保存一副牌
3.使用循环生成这副牌
牌可以设计为一个ArrayList,每个字符串为一张牌。 每张牌由花色数字两部分组成,我们可以使用花色集 合与数字集合嵌套迭代完成每张牌的组装。 牌由Collections类的shuffle方法进行随机排序
2.洗牌
将牌的顺序打乱
3.发牌
1.定义3个集合表示3个玩家
2.定义一个集合表示底牌
3.交替发牌
将每个人以及底牌设计为ArrayList,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌
4.看牌
直接打印每个集合。
课堂代码:
// 1.定义牌类
public class Poker {
private String color;
private String number;
public Poker() {
}
public Poker(String color, String number) {
this.color = color;
this.number = number;
}
@Override
public String toString() {
return color + number;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
import java.util.ArrayList;
import java.util.Collections;
public class Demo04 {
public static void main(String[] args) {
// 1.创建一副牌
// 1.定义牌类
// 2.创建集合,用于保存一副牌
ArrayList<Poker> pokers = new ArrayList<>();
// 3.使用循环生成这副牌
pokers.add(new Poker("大?", ""));
pokers.add(new Poker("小?", ""));
String[] colors = new String[] {"♠", "♥", "♣", "♦"};
String[] numbers = new String[] {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};
// 一个数字要和所有花色组合
for (String number : numbers) {
// 2, A
for (String color : colors) {
// "♠", "♥", "♣", "♦"
Poker poker = new Poker(color, number);
pokers.add(poker);
}
}
// 打印集合,看生成的一副牌
System.out.println(pokers);
// 2.洗牌
// 将牌的顺序打乱
// Collections类:
// public static void shuffle(List<?> list): 将指定的集合中的元素随机交换位置
Collections.shuffle(pokers);
System.out.println("洗牌后: " + pokers);
// 3.发牌
// 1.定义3个集合表示3个玩家
ArrayList<Poker> player01 = new ArrayList<>();
ArrayList<Poker> player02 = new ArrayList<>();
ArrayList<Poker> player03 = new ArrayList<>();
// 2.定义一个集合表示底牌
ArrayList<Poker> diPai = new ArrayList<>();
/*
3.交替发牌
0 1 2 3 4 5 6 7 8 9 10 ... 51 52 53
[♦4, ♠Q, ♣10, ♠A, ♥2, ♠3, ♠K, ♠10, ♥J, ♦9, ♦5, ♦2, 大?, ♣8, ♥10, ♦A, ♣]
根据索引发牌,规律
玩家1: 0,3,6 索引 % 3 == 0
玩家2: 1,4,7 索引 % 3 == 1
玩家3: 2,5,8 索引 % 3 == 2
*/
for (int i = 0; i < pokers.size(); i++) {
// i是索引
// poker是i索引对应的牌
Poker poker = pokers.get(i);
if (i >= 51) {
diPai.add(poker);
} else if (i % 3 == 0) { // 玩家1
player01.add(poker);
} else if (i % 3 == 1) { // 玩家2
player02.add(poker);
} else if (i % 3 == 2) { // 玩家3
player03.add(poker);
}
}
// 看牌: 打印集合
System.out.println("玩家1: " + player01);
System.out.println("玩家2: " + player02);
System.out.println("玩家3: " + player03);
System.out.println("底牌3: " + diPai);
}
}
05、斗地主_抽取
目标: 抽取斗地主的代码
目前代码全部写再main,逻辑上感觉很清晰,实际上,不方便开发和维护的
我们使用面向对象的思维方式,专门搞一个类负责和牌相关的内容
定义一个扑克牌的工具,专门用来操作牌
课堂代码:
// 1.定义牌类
public class Poker {
private String color;
private String number;
public Poker() {
}
public Poker(String color, String number) {
this.color = color;
this.number = number;
}
@Override
public String toString() {
return color + number;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}
import java.util.ArrayList;
// 定义一个扑克牌的工具,专门用来操作牌
public class PokerTools {
// 创建一副牌的方法
public static ArrayList<Poker> createPoker() {
// 1.定义牌类
// 2.创建集合,用于保存一副牌
ArrayList<Poker> pokers = new ArrayList<>();
// 3.使用循环生成这副牌
pokers.add(new Poker("大?", ""));
pokers.add(new Poker("小?", ""));
String[] colors = new String[] {"♠", "♥", "♣", "♦"};
String[] numbers = new String[] {"2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3"};
// 一个数字要和所有花色组合
for (String number : numbers) {
// 2, A
for (String color : colors) {
// "♠", "♥", "♣", "♦"
Poker poker = new Poker(color, number);
pokers.add(poker);
}
}
// 返还创建好的牌
return pokers;
}
// 发牌和看牌
public static void dealPoker(ArrayList<Poker> pokers) {
// 1.定义3个集合表示3个玩家
ArrayList<Poker> player01 = new ArrayList<>();
ArrayList<Poker> player02 = new ArrayList<>();
ArrayList<Poker> player03 = new ArrayList<>();
// 2.定义一个集合表示底牌
ArrayList<Poker> diPai = new ArrayList<>();
/*
3.交替发牌
0 1 2 3 4 5 6 7 8 9 10 ... 51 52 53
[♦4, ♠Q, ♣10, ♠A, ♥2, ♠3, ♠K, ♠10, ♥J, ♦9, ♦5, ♦2, 大?, ♣8, ♥10, ♦A, ♣]
根据索引发牌,规律
玩家1: 0,3,6 索引 % 3 == 0
玩家2: 1,4,7 索引 % 3 == 1
玩家3: 2,5,8 索引 % 3 == 2
*/
for (int i = 0; i < pokers.size(); i++) {
// i是索引
// poker是i索引对应的牌
Poker poker = pokers.get(i);
if (i >= 51) {
diPai.add(poker);
} else if (i % 3 == 0) { // 玩家1
player01.add(poker);
} else if (i % 3 == 1) { // 玩家2
player02.add(poker);
} else if (i % 3 == 2) { // 玩家3
player03.add(poker);
}
}
// 看牌: 打印集合
System.out.println("玩家1: " + player01);
System.out.println("玩家2: " + player02);
System.out.println("玩家3: " + player03);
System.out.println("底牌3: " + diPai);
}
}
import java.util.ArrayList;
import java.util.Collections;
public class Demo05 {
public static void main(String[] args) {
// 1.创建一副牌
ArrayList<Poker> pokers = PokerTools.createPoker();
// 打印集合,看生成的一副牌
System.out.println(pokers);
// 2.洗牌
// 将牌的顺序打乱
// Collections类:
// public static void shuffle(List<?> list): 将指定的集合中的元素随机交换位置
Collections.shuffle(pokers);
System.out.println("洗牌后: " + pokers);
// 3.发牌
PokerTools.dealPoker(pokers);
}
}
06、数据结构
1、数据结构介绍
数据用什么样的方式组合在一起
2、常见数据结构
栈、队列、数组、链表和红黑树
3、常见数据结构分别来了解一下
1、栈:
stack,又称堆栈,它是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除操作,不允许在其 他任何位置进行添加、查找、删除等操作
简单的说:采用该结构的集合,对元素的存取有如下的特点
先进后出(即,存进去的元素,要在后它后面的元素依次取出后,才能取出该元素)。例如,子弹 压进弹夹,
先压进去的子弹在下面,后压进去的子弹在上面,当开枪时,先弹出上面的子弹,然后才能弹出下 面的子弹。
栈的入口、出口的都是栈的顶端位置。
这里两个名词需要注意:
压栈:就是存元素。即,把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个 位置。
弹栈:就是取元素。即,把栈的顶端位置元素取出,栈中已有元素依次向栈顶方向移动一个位 置。
2、队列
queue,简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而
在表的另一端进行删除
简单的说,采用该结构的集合,对元素的存取有如下的特点:
先进先出(即,存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)。例如,小火 车过山洞,车头先进去,车尾后进去;车头先出来,车尾后出来。
队列的入口、出口各占一侧。例如,下图中的左侧为入口,右侧为出口
[外链图片转存失败(img-98wxMgW4-1563546017464)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563451836131.png)]
3、数组
Array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此空间存放元素。就像是一排出租
屋,有100个房间,从001到100每个房间都有固定编号,通过编号就可以快速找到租房子的人
简单的说,采用该结构的集合,对元素的存取有如下的特点:
查找元素快:通过索引,可以快速访问指定位置的元素
[外链图片转存失败(img-6y6F3EUZ-1563546017465)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563451951724.png)]
增删元素慢
指定索引位置增加元素:
需要创建一个新数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引,复制到新数组对应索引的位置。如下图[外链图片转存失败(img-sE5YLEX0-1563546017467)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563452049854.png)]
指定索引位置删除元素:
需要创建一个新数组,把原数组元素根据索引,复制到新数组对应索引的位置,
原数组中指定索引位置元素不复制到新数组中。如下图[外链图片转存失败(img-yhTi3h5j-1563546017469)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563452096237.png)]
4、链表
链表:linked list,由一系列结点node(链表中每一个元素称为结点)组成,结点可以在运行时i动态生成。 每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。我们常说 的链表结构有单向链表与双向链表,那么这里给大家介绍的是单向链表
简单的说,采用该结构的集合,对元素的存取有如下的特点:
多个结点之间,通过地址进行连接。例如,多个人手拉手,每个人使用自己的右手拉住下个人的左 手,依次类推,这样多个人就连在一起了。
查找元素慢:想查找某个元素,需要通过连接的节点,依次向后查找指定元素
增删元素快:[外链图片转存失败(img-vnMATEAF-1563546017470)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563452219552.png)]
5、红黑树
二叉树:binary tree ,是每个结点不超过2的有序树(tree)
简单的理解,就是一种类似于我们生活中树的结构,只不过每个结点上都最多只能有两个子结点。二叉 树是每个节点最多有两个子树的树结构。顶上的叫根结点,两边被称作“左子树”和“右子树”。如图:[外链图片转存失败(img-Gi4MImGn-1563546017472)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563452302266.png)]
我们要说的是二叉树的一种比较有意思的叫做红黑树,红黑树本身就是一颗二叉查找树,将节点插入 后,该树仍然是一颗二叉查找树。如图:[外链图片转存失败(img-JcbgrOEc-1563546017473)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563452349654.png)]
红黑树可以通过红色节点和黑色节点尽可能的保证二叉树的平衡,从而来提高效率。
07、List接口的特点
目标:学习List接口的特点
讲解:
List接口特点:
1.有索引,它是一个元素存取有序的集合。例如,存元素的顺序是11、22、33。那么集合中,元素的存储就 是按照11、22、33的顺序完成的)
2.存储和取出有顺序,它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是 一个道理)
3.元素可以重复,集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素
使用List接口中的常用方法:
void add(int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
E get(int index) 返回此列表中指定位置的元素。
E remove(int index) 删除该列表中指定位置的元素(可选操作)。
E set(int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
小结:
List接口有哪3个特点?
1.有索引
2.元素可以重复
3.存储和取出有顺序
小贴士:
1.我们在基础班的时候已经学习过List接口的子类java.util.ArrayList类,该类中的方法都是来自List中定义
2.我们之前学习Colletion体系的时候,发现List集合下有很多集合,它们的存储结构不同,这样就导致了这
些集合它们有各自的特点,供我们在不同的环境下使用
课堂代码:
import java.util.ArrayList;
import java.util.List;
public class Demo06 {
public static void main(String[] args) {
// 使用List接口的方法
List<String> list = new ArrayList<>();
list.add("钱大妈");
list.add("老干妈");
list.add("大姨妈");
list.add("大姨妈");
list.add("大姨妈");
list.add("大姨妈");
// void add (int index, E element) 将指定的元素插入此列表中的指定位置(可选操作)。
list.add(0, "钱打野");
System.out.println(list); // [钱打野, 钱大妈, 老干妈, 大姨妈]
// E get (int index) 返回此列表中指定位置的元素。
System.out.println(list.get(2));
// E remove (int index) 删除该列表中指定位置的元素(可选操作)。
System.out.println(list.remove(1)); // 被删除的元素
System.out.println("删除后:" + list); // 删除后:[钱打野, 老干妈, 大姨妈]
// E set (int index, E element) 用指定的元素(可选操作)替换此列表中指定位置的元素。
list.set(1, "老干爹");
System.out.println("修改后: " + list); // 修改后: [钱打野, 老干爹, 大姨妈]
}
}
08、ArrayList底层
目标:学习ArrayList集合的底层结构
看源码
小结:
ArrayList集合的底层结构是什么?
是数组,查询块,增删慢
课堂代码:
import java.util.ArrayList;
public class Demo07 {
public static void main(String[] args) {
/*
public class ArrayList {
Object[] elementData;
public ArrayList() {
this.elementData = {};
}
}
1.ArrayList内部有一个成员变量Object[] elementData;,ArrayList存储数据就是存到了这个数组中.
2.在构造方法中,初始化elementData为没有内容的数组
3.在第一次调用add方法时,数组会初始化为10个长度的数组
4.调用add方法,当数组的容量不够的时候会进行扩容,新的容量是当前的1.5倍,10 -> 15 -> 22 -> 33
*/
// 看源码:ctrl + 鼠标左键
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
list.add(8);
list.add(9);
list.add(10);
list.add(11);
}
}
09、LinkedList的使用
目标:理解LinkedList集合的底层结构
[外链图片转存失败(img-SdKNItS7-1563546017475)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563449414380.png)]
讲解
LinkedList是List的子类,List中的方法LinkedList都是可以使用,这里就不做详细介绍,我们只需要了 LinkedList的特有方法即可。在开发时,LinkedList集合也可以作为堆栈,队列的结构使用
LinkedList的底层:
是链表
LinkedList特有方法:
void addFirst(E e) 在该列表开头插入指定的元素。
void addLast(E e) 将指定的元素追加到此列表的末尾。
E getFirst() 返回此列表中的第一个元素。
E getLast() 返回此列表中的最后一个元素。
E removeFirst() 从此列表中删除并返回第一个元素。
E removeLast() 从此列表中删除并返回最后一个元素。
小结:
1.LinkedList集合的底层结构是什么?
链表,查询慢,增删块
课堂代码:
import java.util.LinkedList;
public class Demo08 {
public static void main(String[] args) {
/*
class LinkedList {
Node<E> first; 第一个节点
Node<E> last; 最后一个节点
}
节点,双向链表
class Node<E> {
E item; // 数据域
Node<E> next; // 下一个节点
Node<E> prev; // 上一个节点
}
LinkedList底层使用的链表.
*/
LinkedList<String> linked = new LinkedList<>();
linked.add("长得帅");
linked.add("张帅");
linked.add("郝帅");
linked.add("都狠帅");
// void addFirst (E e) 在该列表开头插入指定的元素。
linked.addFirst("赵德住");
// void addLast (E e) 将指定的元素追加到此列表的末尾。
linked.addLast("随便");
System.out.println(linked); // [赵德住, 长得帅, 张帅, 郝帅, 都狠帅, 随便]
// E getFirst () 返回此列表中的第一个元素。
System.out.println(linked.getFirst()); // 赵德住
// E getLast () 返回此列表中的最后一个元素。
System.out.println(linked.getLast()); // 随便
// E removeFirst () 从此列表中删除并返回第一个元素。
linked.removeFirst();
// E removeLast () 从此列表中删除并返回最后一个元素。
linked.removeLast();
System.out.println(linked);
}
}
10、Vector基本使用
目标:了解Vector的特点和Enumeration的使用
讲解:
Vector底层使用的是数组,被同步,效率低,所以被淘汰了
java.util.Vector集合数和ArrayList一样底层使用数组结构。元素增删慢,查找快,与ArrayList不同的Vector 是线程安全的,速度慢,工作中很少使用。
Enumeration elements() 返回此Vector的枚举(迭代器的前身)
小结:
1.Vector的特点?
Vector底层使用的是数组,被同步,效率低
2.Enumeration的作用?
相当于迭代器,可以获取集合的元素
3.Enumeration的2个方法?
hasMoreElements: 判断是否有下一个元素
nextElement(): 获取下一个元素
课堂代码:
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
public class Demo09 {
public static void main(String[] args) {
Vector<String> vec = new Vector<>();
vec.add("刘德华");
vec.add("张学友");
vec.add("黎明");
vec.add("郭富城");
// 迭代器
Iterator<String> itr = vec.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
// Enumeration:作用和迭代器是一样的,可以获取集合的元素
// hasMoreElements: 判断是否有下一个元素
// nextElement(): 获取下一个元素
// elements()得到Enumeration
Enumeration<String> enu = vec.elements();
while (enu.hasMoreElements()) {
System.out.println(enu.nextElement());
}
}
}
11、HashSet基本使用
目标:学习Set接口的特点
Set接口特点:
1.没有索引
2.元素不可重复
HashSet 是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存储和查找性能。保证 元素唯一性的方式依赖于: hashCode 与 equals 方法
目标:学习HashSet的基本使用
讲解:
Set接口实现类:
HashSet
HashSet类说明:
底层是哈希表结构
1.没有索引
2.元素不可重复
3.存储和取出没有顺序
Set接口的方法:
boolean add(E e) 添加一个元素
boolean remove(Object o) 删除一个元素
注意:
没有修改的方法,也没有获取一个元素的方法,只能通过迭代器来获取数据
小结:
1.说出Set集合特点?
1.没有索引
2.元素不可重复
3.存储和取出没有顺序
2.HashSet如何取出数据?
使用迭代器
课堂代码:
import java.util.HashSet;
import java.util.Iterator;
public class Demo10 {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
hs.add("王昭君");
hs.add("杨玉环");
hs.add("貂蝉");
hs.add("西施");
hs.add("西施");
hs.add("西施");
hs.add("西施");
// hs.remove("杨玉环");
// 使用迭代器获取数据
Iterator<String> itr = hs.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
12、LinkedHashSet基本使用
目标:学习LinkedHashSet的使用
我们知道HashSet保证元素唯一,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?
在HashSet下面有一个子类 java.util.LinkedHashSet ,它是链表和哈希表组合的一个数据存储结构
小结:
LinkedHashSet的特点?
1.没有索引
2.元素不能重复
3.存储和取出有顺序
import java.util.Iterator;
import java.util.LinkedHashSet;
public class Demo11 {
public static void main(String[] args) {
LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("cc");
lhs.add("bb");
lhs.add("aa");
lhs.add("dd");
// 取出来
Iterator<String> itr = lhs.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
// 增强for
for (String el : lhs) {
System.out.println(el);
}
}
}
13、Object类的HashCode方法
目标:能够重写hashCode方法
ctrl + f12看类里面的成员变量和成员方法
讲解:
Object类:
public native int hashCode(); 返回对象的哈希码值。
对象的hashCode相当于人的身份证
默认情况对象的hashCode就是对象的内存地址
我们会重写hashCode,让hashCode值和对象的内容相关
hashCode可能会重复,我们要尽量避免hashCode相同
小结
1.Object类中的hashCode方法默认与什么相同?
2.如何重写hashCode方法?
快捷键: alt + insert -> equals() and hashCode()
课堂代码:
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 重写hashCode
// @Override
// public int hashCode() {
// return 31 * age + name.hashCode();
// }
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
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;
}
}
public class Demo12 {
public static void main(String[] args) {
// Person p1 = new Person("凤姐", 18);
// System.out.println(p1); // 打印对象的地址: 50cbc42f
// System.out.println(p1.hashCode()); // 打印对象的hashCode: 1355531311
// System.out.println(Integer.toHexString(p1.hashCode())); // 打印对象的hashCode的十六进制: 50cbc42f
Person p2 = new Person("a", 18);
Person p3 = new Person("b", 17);
System.out.println(p2.hashCode());
System.out.println(p3.hashCode());
// String类已经重写了hashCode
System.out.println("abc".hashCode());
System.out.println("cba".hashCode());
System.out.println("通话".hashCode()); // 1179395
System.out.println("重地".hashCode()); // 1179395
}
}
14、哈希表的存储元素过程
目标:学习哈希表存储元素的过程
[外链图片转存失败(img-BffUet23-1563546017478)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1563450903830.png)]
讲解:
HashSet底层是哈希表.
小结:
1.说出哈希表存储元素的过程(哈希表判断元素唯一的原理)
1.如果hashCode不相同,直接存储
2.如果hashCode相同,调用equals
2.1 equals返回false,存储
2.2 equals返回true,不存储
注意:
只有底层使用哈希表结构的集合,才需要重写hashCode和equals.确保元素不重复(数据存HashSet/LinkedHashSet才需要重写)
如果元素是存储到ArrayList,LinkedList,不需要重写.
课堂代码:
import java.util.HashSet;
public class Demo13 {
public static void main(String[] args) {
HashSet<String> hs = new HashSet<>();
System.out.println("王健林".hashCode()); // 29089949
System.out.println("王林".hashCode()); // 943468
System.out.println("通话".hashCode()); // 1179395
System.out.println("重地".hashCode()); // 1179395
System.out.println("王健林".hashCode()); // 29089949
hs.add("王健林");
hs.add("王林");
hs.add("通话");
hs.add("重地");
hs.add("王健林");
System.out.println(hs);
}
}
15、HashSet存储Student
目标:
创建4个学生存储到HashSet中,学生包含姓名,年龄和分数属性,姓名,年龄和分数相同的人看做同一人,不存储
讲解:
1.定义学生类
2.创建一个HashSet
3.创建4个学生对象
4.将学生对象添加到HashSet集合中
小结:
当我们的元素要存储到HashSet中,HashSet底层使用哈希表,通过元素的HashCode和equals来判断元素是否重复.所以我们自定义的类放到HashSet中时,需要重写hashCode和equals
课堂代码:
// 1.定义学生类
public class Student {
private String name;
private int age;
private double score;
public Student() {
}
public Student(String name, int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
if (Double.compare(student.score, score) != 0) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result;
long temp;
result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
temp = Double.doubleToLongBits(score);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
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;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
import java.util.HashSet;
import java.util.Iterator;
public class Demo14 {
public static void main(String[] args) {
// 2.创建一个HashSet
HashSet<Student> stus = new HashSet<>();
// 3.创建4个学生对象
Student s1 = new Student("张三", 18, 99);
Student s2 = new Student("李四", 19, 77);
Student s3 = new Student("王五", 16, 66);
Student s4 = new Student("赵六", 66, 66);
Student s5 = new Student("赵六", 66, 66);
// s4/s5是两个对象,目前学生类没有重写hashCode,hashCode默认和对象的内存地址一样
// s4/s5是两个对象,内存地址不一样,意味着hashCode不一样.认为是不同的对象
// 4.将学生对象添加到HashSet集合中
stus.add(s1);
stus.add(s2);
stus.add(s3);
stus.add(s4);
stus.add(s5);
Iterator<Student> itr = stus.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
16、如何选择集合
到目前为止我们学习了常用的集合:
ArrayList,LinkedList,Vector,HashSet,LinkedHashSet
小结:
如何选择集合?
1.如果元素不能重复使用:
HashSet,LinkedHashSet
2.如果元素可以重复
2.1 如果查询多使用: ArrayList
2.2 如果增删多使用: LinkedList
不知道就使用ArrayList
17、总结
能够使用迭代器对集合进行取元素
1.获取迭代器
2.循环判断是否有下一个元素
3.取出下一个元素
能够说出List集合特点
1.元素可以重复
2.存储和取出由顺序
3.有索引
能够说出常见的数据结构
栈,队列,数组,链表,红黑树,哈希表
能够说出数组结构特点
查询快,增删慢
能够说出栈结构特点
先进后出
能够说出队列结构特点
先进先出
能够说出单向链表结构特点
查询慢,增删快
能够说出Set集合的特点
1.没有索引
2.元素不可重复
能够说出哈希表的特点
数组和链表组成
使用HashSet集合存储自定义元素
Student s1 = new Student("张三", 18, 99);
Student s2 = new Student("李四", 19, 77);
Student s3 = new Student("王五", 16, 66);
Student s4 = new Student("赵六", 66, 66);
Student s5 = new Student("赵六", 66, 66);
// s4/s5是两个对象,目前学生类没有重写hashCode,hashCode默认和对象的内存地址一样
// s4/s5是两个对象,内存地址不一样,意味着hashCode不一样.认为是不同的对象
// 4.将学生对象添加到HashSet集合中
stus.add(s1);
stus.add(s2);
stus.add(s3);
stus.add(s4);
stus.add(s5);
Iterator<Student> itr = stus.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
}
}
# 16、如何选择集合
到目前为止我们学习了常用的集合:
ArrayList,LinkedList,Vector,HashSet,LinkedHashSet
#### 小结:
如何选择集合?
1.如果元素不能重复使用:
HashSet,LinkedHashSet
2.如果元素可以重复
2.1 如果查询多使用: ArrayList
2.2 如果增删多使用: LinkedList
不知道就使用ArrayList
# 17、总结
#### 能够使用迭代器对集合进行取元素
1.获取迭代器
2.循环判断是否有下一个元素
3.取出下一个元素
#### 能够说出List集合特点
1.元素可以重复
2.存储和取出由顺序
3.有索引
#### 能够说出常见的数据结构
栈,队列,数组,链表,红黑树,哈希表
#### 能够说出数组结构特点
查询快,增删慢
#### 能够说出栈结构特点
先进后出
#### 能够说出队列结构特点
先进先出
#### 能够说出单向链表结构特点
查询慢,增删快
#### 能够说出Set集合的特点
1.没有索引
2.元素不可重复
#### 能够说出哈希表的特点
数组和链表组成
#### 使用HashSet集合存储自定义元素
重写元素的hashCode和equals方法