杜铁岭:
一 i笔记 1. 数据存储的常用结构有:栈,队列,数组,链表和红黑树 2. 栈:先进后出 (入口和出口在同一侧) 3. 队列:先进先出 (入口和出口在集合的两侧) 4. 数组:查询快(数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引 可以快速查找某一个元素),增删慢(数组的长度是固定的,我们想要增加/删除一个元素,必须 创建一个新数组,把原数组的数据复制过来 5. 链表:查询慢(链表中的地址不是连续的,每次查询元素,都必须从头开始查询),增删快(链表 结构,增加/删除一个元素,对链表的整体结构没有影响,所以增删快). 6. 链表中的每一个元素也称之为一个节点 一个节点包含了一个数据源(存储数组),两个指针域(存储地址) 自己的地址/数据/下一个节点的地址 7. 链表分为两种 单向链表:链表中只有一条链子,(连接所有元素),不能保证元素的顺序(存储 元素和取出元素的顺序有可能不一致) 双向链表:链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合 8. 二叉树:分支不能超过两个 左边可以叫:左孩子 左子树 9. 排序树/查找树 在二叉树的基础上,元素是有大小顺序的 左子树小,右子树大 10. 平衡树:左孩子的数量和右孩子相等 11. 不平衡树:左孩子!=右孩子 12. 红黑树: 特点: 趋近于平衡树,查询的速度非常的快,查询叶子节点大次数和小次数不能超过2倍 约束: 1. 节点可以是红色的或者黑色的 2. 根节点是黑色的 3. 叶子节点(空节点)是黑色的 4. 每个红色的节点 的子节点都是黑色的 5. 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同 13.java.util.List 接口 extends Collection接口 List接口的特点: 1. 有序的集合,存储元素和取出元素的顺序是一致的. 2. 有索引,包含了一些带索引的方法 3. 允许存储重复的元素 List接口中带有索引的方法(特有)
注意: 操作索引的时候,一定要防止索引越界异常 三种异常: IndexOutOfBoundsException索引越界异常 ArrayIndexOutofBoundsException数组索引越界异常 StringIndexOutofBoundsException 字符串索引越界异常 14.ArrayList集合 此实现不是同步的,多线程意 味着效率高速度快(底层是一个数组结构,查 询快增删慢) 15.LinkedList List接口的链表实现(查询慢,增删快),注意,此实现不是同步的,多线程-->速 度快,有大量操作首尾元素的方法 特点: 1. 底层是一个链表结构:查询慢,增删快 2. 里边包含了大量操作首尾元素的方法 注意:使用LinkedList集合特有的方法,不能使用多态 添加: 创建 LInkedList 集合对象 等效push/addFirst (E e):将指定元素插入此列表的开头 等效addList /add 获取: getFirst 获取并返回第一个元素 getLast 在清空以后再获取会抛出 NoSuchElementException获取元素异常 移除并返回: removeFirst/pop removeLast 16. Vector集合底层是一个数组 单线程 1.2版本实现了List接口 17. Set extends Collection接口 特点:1.不允许存储重复的元素 2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历 18. HashSet 哈希表结构 无序结构 此实现也不是同步的(多线程) 特点:是一个无序的集合,存储元素和去取出元素的顺序有可能不一致 底层是一个哈希表结构(查询的速度非常快 ) 19. HashSet集合存储数据的结构(哈希表) 20. 哈希值:是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模 拟出来的得到的地址,不是数据实际存储的物理地址). 在Object类有一个方法,可以获取对象的哈希值.
int hashCode() 返回该对象的哈希码值. public native int hashCode(); native :代表方法调用的是本地操作系统的方法. 21.String类的哈希值 String 类重写Object类的hashCode方法 22.jdk 1.8版本之前:哈希表= 数组+链表 Jdk1.8版本之后:哈希表 = 数组+链表 哈希表 = 数组+红黑树(提高查询的速度) 哈希表的特点:速度快 数据结构:把元素进行了分组.(相同哈希值的元素是一组)链表/红黑树结构把相同哈希值的元 素连接到一起 两个元素不同,但是哈希值相同 哈希冲突 如果链表的元素超过了8位 那么就会把链表转化为红黑树(提高查询速度) 23. Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals方法,判 断元素是否重复 24. LinkedHashSet集合的特点: 底层是一个哈希表(数组+链表/红黑树) + 链表:多了一条链表(记录元素的存储顺序),保证元 素有序 25. 可变参数:是jdk1.5之后出现的新特性 26. 使用前提: 当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用使用可变参数 使用格式: 修饰符 返回值类型 方法名(数据类型... 变量名){} 可变参数的原理: 可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些 参数. 传递参数个数,可以是0个(不传递),1,2...多个 [ 中括号代表一个数组 可变参数的注意事项 1. 一个方法的参数列表,只能有一个可变参数 2. 如果方法的参数有多个,那么可变参数必须卸载参数列表的末尾 可变参数的终极写法 参数列表(Object...obj) 27. Collections sort方法参数默认是 List 28. 注意:sort 使用前提
被排序的集合里边存储的元素如果是自己定义的类),必须实现Comparable,重写接口中的方 法compareTo定义排序的规则 Comparable接口的排序规则 自己(this)- 参数:升序 Comparable:自己(this)和别人(参数)比较,自己需要事先Comparable接口,重写比较的规 则compareTo方法 Comparator:相当于找一个第三方的裁判,比较两个 前减后 升序排序 后减前 降序排序 二 课堂笔记 数据结构:就是数据的存储方式 栈特点:先进后出(FILO First In Last Out) 栈顶 入口 出口 模拟 栈底 存储元素到集合 入栈\压栈 取出集合中元素 出栈\弹栈 队列:先进先出 可用于处理高并发 数组: 查询快:数组的地址是连续,我们通过数组的首地址,可以找到数组,通过数组的索引可以 快速查找某一个元素 增删快:数组的长度是固定的,我们想要增加/删除一个数组,必须创建一个新数组,把原数 组的数据复制复制过来 链表: 查询慢:链表中地址不是连续的,每次查询元素,都必须从头开始查询 增删快:链表结构增加/删除一个元素,对链表的整体结构没有影响,所以增删快 链表中的每一个元素也称之为一个节点 一个节点包含了一个数据源(存储数据),两个指针域(存储地址) 单向链表:链表中只有一条链子,不能保证元素的顺序(存储元素和取出元素的顺序有可能不一 致) 双向链表:链表中有两条链子,有一条链子是专门记录元素的顺序,是一个有序的集合 链表查询 查询只能一个地址值接着一个地址值查询 节点 : 内存中不连续 (Node/Entry ) 单向链表: 只知道下一个节点地址值 双向链表:知道上一个和下一个节点的地址值 红黑树:是一种 平衡 二叉 查找 树
二叉树:分支不能超过两个 树根 左孩子/左子树 右孩子/右子树 树叶 排序树/查找树(查询速度快): 在二叉树的基础上,元素是有大小顺序的 左子树小,右子树大 平衡树:左孩子和右孩子数量相等 不平衡树:左孩子和右孩子数量不相等 红黑树: 特点:趋近于平衡树,查询的速度非常快,查询叶子节点大次数和小次数不能超过二倍 约束条件: 1. 节点可以是红色的或者黑色的 2. 根节点是黑色的 3. 叶子节点(空节点)黑色的 4. 每个共色的节点的子节点都是黑色的 5. 任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同 添加元素: 先和节点值进行比较 如果新添加的元素之比当前节点元素值小,则放在当前节点的左边 叶子节点 (头上) 到根节点 数相同 2-节点:节点多只有2个子节点 3-节点:节点多只有3个子节点 (节点可以存两个数) 可以有两个分支 被提升上来的节点是红色的(线也是红色的) 树的遍历: 从根节点向左走一直到走不动 返回当前节点的值 往右走 返回上一层节点 迭代; 查询 增删 需要自动排序 比链表 效率高 List集合 (重写了toString方法) Java.util.List接口extends Collection接口 特点:
1. 有序的集合,存储元素和取出元素的顺序是一致的. (存取顺序) 2. 有索引,包含了一些索引的方法 3. 允许存储重复的元素 注意: 操作索引的时候,一定要防止索引越界异常 Add 若原有索引上有元素,后面元素向后移 (数组结构)ArrayList(属于List子体系)集合 java.util.ArrayList 底层是一个数组 查询快,增删满 多线程 效率高速度快 特点: 线程不安全,效率高 API java.util.List<E>接口: // 常用特有成员方法 (都是按照索引来操作的) public?void?add(int?index,?E?element): 将指定的元素, 添加到该集合中的指定位置上 public?E?get(int?index): 返回集合中指定位置的元素 public?E?remove(int?index): 移除列表中指定位置的元素, 返回的是被移除的元素 public?E?set(int?index,?E?element): 用指定元素替换集合中指定位置的元素, 返回值的更新前的元素 java.util.LinkedList<E>类: 链表结构, 查询慢, 增删快 // 特有成员方法(主要操作开头和末尾元素) void?addFirst(E?e): 将指定元素插入此列表的开头 void?addLast(E?e): 将指定元素添加到此列表的结尾 E?getFirst(): 返回此列表的第一个元素 E?getLast(): 返回此列表的后一个元素 E?removeFirst(): 移除并返回此列表的第一个元素 E?removeLast(): 移除并返回此列表的后一个元素 E?pop(): (其实就是removeFirst())从此列表所表示的堆栈处弹出一个元素 栈stack void?push(E?e): (其实就是addFirst())将元素推入此列表所表示的堆栈 java.util.Collections类: 操作集合的工具类 // 静态方法 static?<T>?boolean?addAll(Collection<T>?c,?T...?elements):往集合中添加一些元素 static?void?shuffle(List<?>?list) :打乱集合顺序 static?<T>?void?sort(List<T>?list) :将集合中元素按照默认规则排序 static?<T>?void?sort(List<T>?list,Comparator<??super?T>?c):将集合中元素按照指定规则排序 LinkedList 多线程 底层是一个链表结构,查询慢,增删快 里边包含了大量操作守卫元素的方法 注意:不要用多态操作特有方法 pop--> 弹出 removefirst push 压 -->addfirst 线程不安全效率高 Vector 同步的 -->单线程
Set接口 继承了Collections java.util.Set 特点: 1.不允许存储重复的元素 2.没有索引,没有带索引的方法,不能使用普通的for循环遍历 HashSet特点: 无序集合,存储元素和取出元素的顺序有可能不一致 底层是一个哈希表结构(查询的速度非常的快) 哈希表 = 数组 + 链表 或 红黑树 哈希算法:把任意的东西通过某种计算方式,转换为整数,通过数字代表这个事物 哈希值:是一个十进制的整数,由系统随机给出,是一个逻辑地址,是模拟出来得到的地址,不是 实际存储的的物理地址. native :代表该方法调用的是本地操作系统的方法 String类重写Objec类的hashCode方法 不同内容算出(两个元素不同)哈希值一样 ---> 哈 希冲突 哈希表特点:速度快 Jdk 1.8之前 哈希表 = 数组 + 链表 1.8后 = 数组 + 红黑树(提高查询速度) 如果挂的(链表长度超过了8位)元素超过8位,把链表转化成红黑树--->提高查询速度 数组的元素是一个链表 集合重写了toString 哈希表初始容量 16个 去重 应用Set 生成 equals 和 hashcode Hashset 存取顺序不一致 Linkedhashset 存取顺序一致 多一条链表 记录元素的存储顺序 可变参数:jdk1.5之后出现的新特性 使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变 参数. 使用格式:定义方法时使用 修饰符 返回值类型 方法名(数据类型...变量名){} 可变参数的原理: 可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些 参数. 传递的参数个数就,可以是0个(不传递)1,2,...多个 注意事项: 1. 一个方法的参数列表,只能有一个可变参数
2. 如果方法的参数有多个,那么可变参数必须写在参数列表的末尾. 可变参数的特殊写法:(终极) 参数列表(Object obj) Collections addAll(集合名,1,2,3) Set集合 (哈希值计算出来固定就放在那) 不可排序 List集合可排序 注意: Sort使用前提 自定义对象想要排序,必须实现Comparable,重写接口中的Comparato方法 返回0 认为元素都是相同的 自定义比较的规则,比较两个人的年龄(this,参数) Return this.getAge() - o.getAge() 升序 Comparable规则: 自己(this)-参数:升序 单项链表:方向,遍历的方向,只能从前往后遍历链表 2个成员变量 一个存数据,一个存下一个 节点的地址值 后一个存null 整个链表的地址值是第一个节点的地址值 双向链表:既能从前往后,也能从后往前遍历 存上下节点的地址值 数据 还有本身地址值 三.老师笔记 day03 List Set 今日内容 数据结构 集合 List集合 Set集合 Collections集合工具类 数据结构 数据结构: 就是数据的存储方式 不同的数据结构代表了不同的存储方式 不同的数据结构中, 会有不同的存入, 取出, 查找的方式和效率, 数据的存放方式也不同 如薯片, 可以用长纸筒装, 也可以用塑料包装袋装, 在两种容器中的存储方式就不同, 放入和取出的方式也 不一样
栈 知识点:
栈结构存入和取出数据的顺序有什么特点 栈结构适用于什么场景 总结: 栈: ^ | | v | | 出入口在同一端 | +---------+ | | | 3 | | | +---------+ | | +---------+ | | | 2 | | 栈 | +---------+ | | +---------+ | | | 1 | | | +---------+ | +-------------+
栈的特点: 先进后出 (FILO, First In Last Out) 入口和出口在同一侧 入栈(压栈): 将元素存入栈 出栈(弹栈): 从栈中取出元素
栈的适用场景:
栈内存 (main方法先进栈调用, main方法中的其他方法都调用完毕后, main才能出栈) 反转内容 (车尾变车头, 进去再出来就反转了) 补充:
队列 知识点:
队列结构存入和取出数据的顺序有什么特点 队列结构适用于什么场景 总结:
队列:
入口 出口 ---------------------------------------------- +---------+ +---------+ +---------+ ----> | 3 | | 2 | | 1 | ----> +---------+ +---------+ +---------+ ----------------------------------------------
队列的特点: 先进先出 (FIFO, First In First Out) 入口和出口在两端 队列的适用场景: 秒杀, 抢购 在线售票 处理高并发场景
补充:
数组 知识点:
数组结构增删和查询数据有什么特点 数组结构适用于什么场景 总结:
数组: 0x01 0x02 0x03 0x04 0x05 +-----+-----+-----+-----+-----+ | "a" | "b" | "c" | "d" | "e" | +-----+-----+-----+-----+-----+ 0 1 2 3 4 数组的特点: 查询快: 通过 (第一个元素地址值 + 索引) 可以快速计算出该索引元素的地址值 增删慢: 增加一个元素, 要创建长度+1的新数组, 然后将原数组元素复制到新数组, 然后存入新元素; 删除 类似 // 添加元素 +-----+-----+-----+-----+-----+ | "a" | "b" | "c" | "d" | "e" | 如果要添加元素"f"
+-----+-----+-----+-----+-----+ +-----+-----+-----+-----+-----+-----+ | "a" | "b" | "c" | "d" | "e" | "f" | 创建一个新数组, 将原数组元素复制进去, 然后存入新元素 +-----+-----+-----+-----+-----+-----+ 数组的适用场景: 查询多, 增删少的数据存储场景 国内城市
补充:
链表 知识点:
链表结构增删和查询数据有什么特点 链表由什么组成 什么是单向链表 什么是双向链表 链表结构适用于什么场景 总结:
链表: 链表由多个 节点(Node / Entry) 组成 +-----+-----+-----+ +-----+-----+ | | | | |数据 | | +-----+-----+-----+ +-----+-----+
单向链表: 每个节点存储 数据 和 下一个节点的地址值
链表 = 0x11
0x11 0x44 0x88 +-----+-----+ +-----+-----+ +-----+-----+ | "a" | 0x44| --> | "b" | 0x88| --> | "c" | null| +-----+-----+ +-----+-----+ +-----+-----+ 数据 下一个 数据 下一个 数据 下一个
双向链表: 每个节点存储 数据, 上一个节点地址值 和 下一个节点地址值 0x11 0x44 0x88 +-----+-----+-----+ +-----+-----+-----+ +-----+-----+-----+ |null | "a" | 0x44| <--> |0x11 | "b" | 0x88| <--> |0x44 | "c" | null| +-----+-----+-----+ +-----+-----+-----+ +-----+-----+-----+ 上一个 数据 下一个 上一个 数据 下一个 上一个 数据 下一个
链表的特点: 查询慢: 要找到其中某个节点, 只能从第一个节点一个一个向后寻找 增删快: 只需要修改保存的下一个节点的地址值, 就可以快速完成增删 // 删除结点 +---+ +---+ +---+ | 1 |----| 2 |----| 3 | +---+ +---+ +---+
+---+ +---+ | 1 |-------------| 3 | +---+ +---+ +---+ | 2 | +---+ 链表的适用场景: 查询少, 增删多的场景 链表可以实现栈和队列的结构, 因为栈和队列增删频繁 补充:
代码中链表节点的实现:
// 单向链表的节点 class Node<T> { T data; // 存储的数据 Node next; // 下一个节点的地址值 }
// 双向链表的节点 class Node<T> { T data; // 存储的数据 Node before; // 上一个节点的地址值 Node after; // 下一个节点的地址值 } 红黑树 知识点:
红黑树结构有什么特点 红黑树结构适用于什么场景 总结:
红黑树: 是一种 平衡 二叉 查找 树 平衡: 左子节点和右子节点数量相等 二叉: 每个节点多有2个子节点 查找: 节点存储的元素是按照大小顺序存储的 特点: 元素存储过程中就完成了大小排序 查询比链表快, 增删比数组快 (数组和链表的折中)
红黑树的适用场景: 查询和增删都有, 需要元素自动排序的场景
树的遍历:
补充:
代码中树节点的实现
// 树的节点 class Entry<T> { T data; // 存储的数据 Entry left; // 左子节点的地址值 Entry right; // 右子节点的地址值 Entry parent; // 父节点的地址值 } List集合 List介绍和常用方法 知识点:
List集合体系有什么特点 List接口中特有的按照索引操作的方法有哪些
总结:
List集合体系的特点: 1. 元素存取有序 (存入和取出元素的顺序一致) 3 2 1 3 2 1 2. 元素可以重复 3 2 2 1 3. 有索引 List子体系中的实现类都具有上述特点
java.util.List接口: // 常用特有成员方法 (都是按照索引来操作的) void add(int index, E element): 将指定的元素, 添加到该集合中的指定位置上 E get(int index): 返回集合中指定位置的元素 E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素 E set(int index, E element): 用指定元素替换集合中指定位置的元素, 返回值的更新前的元素 补充:
ArrayList集合的特点 知识点:
ArrayList底层使用的是什么数据结构, 有什么特点 ArrayList适用于什么场景 总结:
ArrayList底层的数据结构:
数组 ArrayList的特点: 查询快 增删慢 线程不安全, 效率高 ArrayList适用场景: 存储的数据"查询多, 增删少"的场景. 如用一个ArrayList存储中国城市名称 补充:
LinkedList集合的特点和特有方法 知识点:
LinkedList底层使用的是什么数据结构, 有什么特点 LinkedList适用于什么场景 LinkedList有哪些特有方法 总结:
LinkedList底层的数据结构: 链表 LinkedList的特点: 查询慢 增删快 线程不安全, 效率高 LinkedList适用场景: 存储的数据"查询少, 增删多"的场景. 如用LinkedList实现栈或队列 java.util.LinkedList<E>类: 链表结构, 查询慢, 增删快 // 特有成员方法(主要操作开头和末尾元素) void addFirst(E e): 将指定元素插入此列表的开头 void addLast(E e): 将指定元素添加到此列表的结尾 E getFirst(): 返回此列表的第一个元素 E getLast(): 返回此列表的后一个元素 E removeFirst(): 移除并返回此列表的第一个元素 E removeLast(): 移除并返回此列表的后一个元素
E pop(): (其实就是removeFirst())从此列表所表示的栈中弹出一个元素 void push(E e): (其实就是addFirst())将元素添加到此列表所表示的栈中 补充:
5分钟练习: 测试LinkedList特有方法
需求: 创建LinkedList集合, 添加元素1,2,3, 测试特有方法: void addFirst(E e): 将指定元素插入此列表的开头 void addLast(E e): 将指定元素添加到此列表的结尾 E getFirst(): 返回此列表的第一个元素 E getLast(): 返回此列表的后一个元素 E removeFirst(): 移除并返回此列表的第一个元素 E removeLast(): 移除并返回此列表的后一个元素 E pop(): (其实就是removeFirst())从此列表所表示的栈中弹出一个元素 void push(E e): (其实就是addFirst())将元素添加到此列表所表示的栈中 代码:
public class Test { public static void main(String[] args) { // 创建LinkedList集合 LinkedList<Integer> list = new LinkedList<>();
list.add(1); list.add(2); list.add(3); System.out.println("初的集合:"+list);
// void addFirst(E e): 将指定元素插入此列表的开头 list.addFirst(0); System.out.println(list);
// void addLast(E e): 将指定元素添加到此列表的结尾 list.addLast(9); System.out.println(list);
// E getFirst(): 返回此列表的第一个元素 Integer getFirst = list.getFirst();
System.out.println("getFirst:" + getFirst);
// E getLast(): 返回此列表的后一个元素 Integer getLast = list.getLast(); System.out.println("getLast:" + getLast);
// E removeFirst(): 移除并返回此列表的第一个元素 Integer removeFirst = list.removeFirst(); System.out.println("removeFirst:" + removeFirst);
// E removeLast(): 移除并返回此列表的后一个元素 Integer removeLast = list.removeLast(); System.out.println("removeLast:" + removeLast);
// E pop(): (其实就是removeFirst())从此列表所表示的栈中弹出一个元素 Integer pop = list.pop(); System.out.println("pop:" + pop);
// void push(E e): (其实就是addFirst())将元素添加到此列表所表示的栈中 list.push(666); System.out.println(list); } } Vector集合 知识点:
Vector底层使用的是什么数据结构, 有什么特点 总结:
JDK 1.0 版本中只有一个 Vector集合 JDK 1.2 开始增加了Collection集合体系
Vector底层的数据结构: 数组 Vector的特点: 查询慢 增删快 (同步)线程安全, 效率低
Vector目前几乎没人使用 补充:
Set集合体系 HashSet集合 知识点: Set集合体系有什么特点 HashSet有什么特点, 底层采用什么数据结构 HashSet中的add()方法有什么特殊之处
总结:
Set集合体系特点: 1. 元素不可重复 2. 没有索引 HashSet特点: 1. 元素不可重复 2. 没有索引 3. 元素存取无序 (存入和取出顺序有可能不一致) 4. 底层采用 哈希表 结构. (查询快) 哈希表 = 数组 + 链表或红黑树
java.util.HashSet类: // 常用方法 boolean add(E e): 添加元素, 根据元素的 hashCode() 和 equals() 方法判断是否重复. 重复则不添加并 返回false, 不重复则添加并返回true 补充:
5分钟练习: 使用HashSet添加元素 需求: 创建HashSet对象, 存储 5,5,4,4,3,3,2,2,1,1, 使用增强for遍历HashSet集合打印元素, 查看是否和存入顺序 一致, 是否有重复元素
代码:
public class Test { public static void main(String[] args) { // 创建HashSet集合, 用不用多态都行, 因为add方法不是子类特有的 Set<Integer> set = new HashSet<>();
// 添加元素 set.add(5); set.add(5); set.add(4); set.add(4); set.add(3); set.add(3); set.add(2); set.add(2); set.add(1); set.add(1);
// 增强for遍历 for (Integer integer : set) { System.out.println(integer); // 1 2 3 4 5 }
} } HashSet原理: 哈希值
知识点: 哈希表
int hashCode()
什么是哈希值, 哈希值有什么作用 Object类中的 hashCode() 方法有什么作用
总结:
哈希值: 一个十进制数值, 一般是通过将该对象的内部地址转换成一个整数来实现的
public native int hashCode(); 可以调用系统本地代码(C/C++)计算出一个对象地址的哈希值 hashCode()方法的作用 方法内部的算法用于将对象计算为一个哈希值, 便于根据哈希值比较对象是否"相等" 哈希值主要是为了提高对象存储在 哈希表 中的效率 注意: 1. 如果我们不满意Object中的哈希值计算方法, 可以重写hashCode()方法. 但在Java代码中不能直接重写带有 native 的方法, 重写时应该将 native 去掉 @Override public int hashCode() {} 2. hashCode() 方法有可能将"不同的对象"计算出"相同的哈希值", 这称为"哈希冲突", 在出现冲突后, 一 般再通过 equals() 方法来继续判断对象是否"相等" "重地" "通话" 补充:
HashSet原理: 哈希表结构 知识点: JDK 8以前, 哈希表是什么结构 JDK 8及之后, 哈希表是什么结构
总结:
哈希表: JDK 8以前 : 哈希表 = 数组 + 链表 JDK 8及之后 : 哈希表 = 数组 + 链表或红黑树 数组中存储的每个元素, 是哈希值相同的一组节点的链表或红黑树
补充:
HashSet原理: 存储元素不重复的原理 知识点: HashSet集合是如何保证添加元素时不能重复的
总结:
HashSet集合保证添加元素不重复的原理:
调用 add(E e) 添加元素时, 先调用 hashCode() 获取哈希值, 和当前HashSet集合中的元素比较 如果哈希值不同, 则认为元素不重复, 添加, 并返回true 如果哈希值相同, 则有可能是哈希冲突, 所以继续调用元素的 equals() 方法和所有哈希值相同的元素 比较 如果 equals() 比较所有元素都没有相同的, 则认为元素不重复, 添加, 并返回true 如果 equals() 比较出有相同的元素, 则认为元素重复, 不添加, 并返回false
补充:
HashSet存储自定义元素的去重 知识点: 我们自定义的JavaBean对象存入HashSet时, 想根据属性值保证不重复, 应该怎么做
总结:
自定义JavaBean对象实现在HashSet中去重: JavaBean默认继承Object类中的 hashCode() 和 equals() 方法, 都是根据对象地址值判断是否重复的 要根据属性值判断是否重复, 应该在JavaBean类中重写 hashCode() 和 equals() 方法, 使其按照属性值 比较 补充:
5分钟练习: 自定义Person类存入HashSet实现去重
需求: 定义Person类: 私有成员变量: 姓名String name, 年龄int age 生成无参/有参构造, set/get方法, toString()方法 生成 hashCode() 和 equals() 方法 定义测试类 创建3个Person对象, 其中2个对象的姓名和年龄均相同, 另外1个对象姓名或年龄不同 创建HashSet集合, 存入3个Person对象, 打印HashSet集合, 查看是否去重 代码:
public class Person {
private String name; private int age;
public Person() { }
public Person(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; }
@Override
public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
// 生成hashCode()和equals()方法, 根据属性值判断是否重复, 用于存储HashSet去重 @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); }
@Override public int hashCode() { return Objects.hash(name, age); } }
public class Test { public static void main(String[] args) { // 创建3个Person对象 Person p1 = new Person("张三", 13); Person p2 = new Person("张三", 13); Person p3 = new Person("张三", 55); // 年龄不同
// 创建HashSet集合 HashSet<Person> set = new HashSet<>(); set.add(p1); set.add(p2); set.add(p3);
// 打印集合, 查看是否去重 System.out.println(set); // [Person{name='张三', age=55}, Person{name='张三', age=13}] } }
LinkedHashSet集合 知识点: LinkedHashSet有什么特点 LinkedHashSet底层是什么数据结构
总结:
LinkedHashSet特点: 1. 元素存取有序 (存入和取出顺序一致) 2. 元素不可重复 3. 没有索引 LinkedHashSet底层数据结构: 哈希表 + 链表 (也就是: 数组 + 链表或红黑树 + 链表) 其中, 哈希表用于存储数据, 额外的链表用于记录元素添加时的先后顺序, 以便在获取元素时保持顺序一 致 补充:
总结: 什么时候用List, 什么时候用Set? 要存储的元素可以重复的, 用List集合: 增删少, 用ArrayList 增删多, 用LinkedList 要存储的数据要求不重复, 或者相对一个集合去重, 用Set集合: 不要求存取顺序一致, 用HashSet 要求存取顺序一致, 用LinkedHashSet 5分钟练习: 使用LinkedHashSet存储元素 需求: 创建LinkedHashSet对象, 存储 5,5,4,4,3,3,2,2,1,1, 使用增强for遍历LinkedHashSet集合打印元素, 查看是 否和存入顺序一致
代码:
可变参数 知识点: 什么是可变参数 可变参数用在哪里, 格式是什么
可变参数的本质是什么 可变参数可以传递的参数个数有什么要求 可变参数的定义位置有什么要求
总结:
可变参数: JDK 5 出现. 指同一个类型参数个数可变的参数 可变参数的本质就是一个"数组" 格式: 用在方法的参数中 修饰符 返回值类型 方法名(int... 变量名) { // 可以直接将 变量名 当作 数组名 使用 } 方法名();
注意事项: 1. 可变参数可以传递的参数个数, 可以是 0个, 1个, 多个 2. 一个方法的参数列表中, 只能有一个可变参数 3. 如果方法的参数有多个, 可变参数必须写在参数列表的后 补充:
Collections集合工具类 Collections集合工具类: addAll(), shuffle() 知识点: Collections集合工具类的常用方法有哪些
总结:
java.util.Collections类: 操作集合的工具类 // 静态方法 static <T> boolean addAll(Collection<? super T> c, T... elements):往集合中添加一些元素 static void shuffle(List<?> list): 打乱集合顺序 static <T> void sort(List<T> list): 将集合中元素按照默认规则排序 static <T> void sort(List<T> list,Comparator<? super T> c):将集合中元素按照指定规则排序 补充:
5分钟练习: 测试addAll()和shuffle()方法 需求: 创建ArrayList集合, 使用Collections.addAll()方法, 向集合中添加1,2,3,4,5 然后调用shuffle()方法打乱该集合的顺序, 打印集合查看效果
代码:
public class Test { public static void main(String[] args) { // 创建ArrayList集合 ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list, 1, 2, 3, 4, 5);
System.out.println(list); // [1, 2, 3, 4, 5]
// 打乱 Collections.shuffle(list);
// 查看打乱后的结果 System.out.println(list); // [4, 2, 3, 1, 5] } } Collections集合工具类: sort(List<T> list) 知识点: sort(List<T> list)方法按照什么规则将元素排序 是不是所有类型的元素都能排序 该方法有什么使用前提 自定义JavaBean对象要想排序, 需要怎么做
总结:
sort(List<T> list): 默认按照"升序"将元素排序 数字, 字母, 都可以按照升序排序 自定义JavaBean对象默认不能排序, 因为不知道如何比较哪个对象大, 哪个对象小
自定义JavaBean对象要想排序, 需要实现 Comparable<E> 接口, 重写 int compareTo(E e) 方法 规则: this-参数: 升序(从小到大) 参数-this: 降序(从大到小) 补充:
5分钟练习: 实现Person排序
需求: 定义Person类, 实现Comparable接口, 泛型为Person: 私有成员变量: 姓名String name, 年龄int age 生成无参/有参构造, set/get方法, toString() 重写int compareTo(E e)方法 方法内部根据Person对象的年龄计算大小 定义测试类 创建3个Person对象, 分别为: 李四, 14 张三, 13 王五, 15 创建ArrayList集合, 存储3个Person对象 调用 Collections.sort() 方法, 对集合排序, 然后使用增强for遍历输出结果, 查看是否排序 代码:
public class Person implements Comparable<Person> { // 让Person自身具有可比较性
private String name; private int age;
public Person() { }
public Person(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; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
@Override public int compareTo(Person o) { /* 规则: this-参数: 升序从小到大 参数-this: 降序从大到小 */ // 按照Person对象的年龄升序排序 // return this.getAge() - o.getAge();
// 按照Person对象的年龄降序排序 return o.getAge() - this.getAge(); } }
public class Test { public static void main(String[] args) { // 创建3个Person对象 Person p1 = new Person("李四", 14);
Person p2 = new Person("张三", 13); Person p3 = new Person("王五", 15);
// 将3个对象存入集合 ArrayList<Person> list = new ArrayList<>(); list.add(p1); list.add(p2); list.add(p3);
System.out.println("排序前:" + list); // 排序 Collections.sort(list); System.out.println("排序后:" + list);
} } Collections集合工具类: sort(List<T> list, Comparator<? super T> ) 知识点:
sort(List<T> list,Comparator<? super T> c) 方法的第二个参数是什么, 如何使用 Comparable接口和Comparator接口有什么区别 自定义JavaBean对象要想利用该方法排序, 需要怎么做 总结:
Comparable接口和Comparator接口区别 Comparable: 让JavaBean自身具有可比较性 (自己和其他人比) Comparator: 定义一个比较器类, 用比较器对象比 (让第三个人来帮两个人比较)
Comparator使用方式: 定义类作为比较器, 实现Comparator<E>接口, 重写 int compare(E o1, E o2) 方法, 泛型为要比较的元 素的类型 在Collections.sort(List<T> list,Comparator<? super T> c)方法中传入自定义比较器对象 规则: o1-o2: 升序(从小到大) o2-o1: 降序(从大到小) 补充:
5分钟练习: 使用Comparator对Person集合排序
需求: 定义Person类: 私有成员变量: 姓名String name, 年龄int age 生成无参/有参构造, set/get方法, toString() 定义测试类 创建3个Person对象, 分别为: 李四, 14 张三, 13 王五, 15 创建ArrayList集合, 存储3个Person对象 调用Collections.sort(List<T> list,Comparator<? super T> c)方法, 对集合排序, 比较器使用匿名内 部类对象方式, 按照Person对象的年龄排序 然后使用增强for遍历输出结果, 查看是否排序 代码:
public class Person {
private String name; private int age;
public Person() { }
public Person(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; }
@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
public class Test { public static void main(String[] args) { // 创建3个Person对象 Person p1 = new Person("李四", 14); Person p2 = new Person("张三", 13); Person p3 = new Person("王五", 15);
// 创建集合添加元素 ArrayList<Person> list = new ArrayList<>(); list.add(p1); list.add(p2); list.add(p3);
System.out.println("排序前:" + list); // 对集合排序 Collections.sort(list, new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { /* 规则: o1-o2: 升序 o2-o1: 降序 */ // 按照年龄升序 // return o1.getAge() - o2.getAge();
// 按照年龄降序 return o2.getAge() - o1.getAge(); } }); System.out.println("排序后:" + list); } } 今日API
java.util.List<E>接口: // 常用特有成员方法 (都是按照索引来操作的) public void add(int index, E element): 将指定的元素, 添加到该集合中的指定位置上 public E get(int index): 返回集合中指定位置的元素 public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素 public E set(int index, E element): 用指定元素替换集合中指定位置的元素, 返回值的更新前的元素
java.util.LinkedList<E>类: 链表结构, 查询慢, 增删快 // 特有成员方法(主要操作开头和末尾元素) void addFirst(E e): 将指定元素插入此列表的开头 void addLast(E e): 将指定元素添加到此列表的结尾 E getFirst(): 返回此列表的第一个元素 E getLast(): 返回此列表的后一个元素 E removeFirst(): 移除并返回此列表的第一个元素 E removeLast(): 移除并返回此列表的后一个元素 E pop(): (其实就是removeFirst())从此列表所表示的堆栈处弹出一个元素 栈stack void push(E e): (其实就是addFirst())将元素推入此列表所表示的堆栈 java.util.Collections类: 操作集合的工具类 // 静态方法 static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素 static void shuffle(List<?> list) :打乱集合顺序 static <T> void sort(List<T> list) :将集合中元素按照默认规则排序 static <T> void sort(List<T> list,Comparator<? super T> c):将集合中元素按照指定规则排序 单列集合体系: Collection接口: 单列集合的根接口, 规定了公共的功能 | |_ List接口: 元素存取有序, 可重复, 有索引 | |_ Vector类: 底层数组, 有索引, 内存空间连续分配, 查询快, 增删慢, 线程安全, 效率低
| |_ ArrayList类: 底层数组, 有索引, 内存空间连续分配, 查询快, 增删慢, 线程不安全, 效率高 | |_ LinkedList类: 底层链表, 查询慢, 增删快 | |_ 遍历 | - toArray(): 可以 | - 普通for: 可以 | - 增强for: 可以 | - 迭代器: 可以 | |_ Set接口: 元素不可重复, 无索引 |_ HashSet类: 底层哈希表, 元素无序, 元素不可重复(用hashCode()和equals()方法来判断) | |_ LinkedHashSet类: 哈希表+链表, 同时具有HashSet的元素不重复, 链表存取有序的特点 | |_ TreeSet类: 底层红黑树结构(存入元素时就会按照元素自然顺序排序). | |_ 遍历 - toArray(): 可以 - 普通for: 不可以, 没有索引, 不能用! - 增强for: 可以 - 迭代器: 可以
今日目标 能够说出List集合特点
1. 元素存取有序 2. 有索引 3. 元素可以重复 能够说出常见的数据结构
栈 队列 数组 链表 红黑树 哈希表 = 数组 + 链表/红黑树 能够说出数组结构特点 查询快 增删慢 能够说出栈结构特点
先进后出 入口出口是同一个 能够说出队列结构特点
先进先出 入口出口在两侧 能够说出单向链表结构特点
|
|