目录
一、Date
1.基础知识
2.主要方法:
二、SimpleDateFormat
1.日期格式化(y年,M月,d天,H小时【0-23】,m分钟,s秒)
2.解析(格式必须一致)
三、集合类
1.数组与集合的区别
2.集合类体系结构
3.Collection
(1)概述
(2)创建
(3)常用方法
(4)迭代器Iterator
(5)增强for
(6)遍历使用场景
4.List集合
(1)特点
(2)主要方法
5.ArrayList
6.LinkedList
7.Set集合
8.TreeSet
(1)特点:
(2)排序规则:
9.HashSet
(1)底层:底层是哈希表
(2)特点
(3)存储结构
10.Map
(1)概述
(2)主要方法
(3)遍历
11.HashMap
(1)概述
(2)主要方法
(3)注意
(4)练习:
12.TreeMap
(1)概述
(2)主要方法
(3)注意
(4)练习
四、数据结构
1.栈
2.队列
3.数组
4.链表
5.树
(1)二叉树(遍历查找)
编辑
编辑
(2)二叉查找树
(3)平衡二叉树
(5)红黑树
6.哈希表
五、泛型 < E >
1.泛型的必要性
六、可变参数
(1)练习
七、不可变集合
1.主要方法 of(JDK9才有)
2.使用
n、练习
1.秒杀活动
2.用Collection集合存储用户对象并遍历
3.有一些字符串{“a”,“ab”,“ac”,“abc”,“bac”},按照字符串长度排序,如果长度相同,按照首字母排序
世界标准时间:原子钟
中国标准时间:世界标准时间+8h
时间换算:1s = 1000ms
计算机的时间原点:1970年1月1日——00:00:00
Date(util包下的),getTime,setTime
Date():当前电脑时间
Date(long):从计算时间原点开始过了多少毫秒的时间
getTime:获取时间对象所对应的毫秒值
setTime:设置时间,传递毫秒值
主要方法:SimpleDateFormat()-默认格式,SimpleDateFormat(String)-自定格式,parse()-解析
Date对象转为2020年1月1日0:0:0这类格式
转化格式
日期 | 转化格式 |
---|---|
1970-1-1 13:12:06 | yyyy-MM-dd 空格 HH:mm:ss |
1970年1月1日 13:12:06 | yyyy年-MM月-dd日 空格 HH:mm:ss |
public class DateDemo {
public static void main(String[] args) {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final String format = simpleDateFormat.format(date);
System.out.println(format);
}
}
与格式化相反
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = "2023-12-29 10:41:46";
final Date parse = simpleDateFormat.parse(dateStr);
System.out.println(parse);
数组长度不可变,集合的长度是可变的(自动扩容)
数组可以存放基本和引用数据类型,
集合只能存放引用类型,要想存储基本数据类型,需要存基本数据类型对应的包装类。
是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现
多态
具体的实现类ArrayList/LinkedList
Collection collection = new ArrayList();
方法名 | 返回值类型 | 说明 |
---|---|---|
add | void | 添加元素 |
remove | 如果移除成功返回true,否则为false | 移除指定元素 |
removeif | default boolean | 条件移除(会遍历集合) |
clear | void | 清空集合 |
contains | boolean | 判断元素是否存在 |
isEmpty | boolean | 判断集合是否为空 |
size | int | 集合长度 |
集合专用遍历方式
常用方法:
方法名 | 返回值类型 | 说明 |
---|---|---|
hasNext() | boolean | 判断当前位置是否有元素可以被取出 |
next() | E | 获取当前位置的元素,并将迭代器对象的索引移到下一个索引位置 |
package api;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo01 {
public static void main(String[] args) {
Collection list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
//获取迭代器对象
//该对象一旦创建,默认指向该集合的0索引/下标处
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
简化数组和Collection集合的遍历
注意点:
JDK5以后,内部原理还是Iterator
只有实现Iterable接口的类才可以使用增强for
修改元素类型的变量值不会影响到集合中的元素
格式:
for(元素数据类型 变量名:数组或Collection集合){
//直接输出变量即可,变量即为元素
}
IDEA快捷使用:
数组/集合.for + 回车
如果需要操作索引,使用for即可
遍历过程中需要删除元素,使用迭代器
仅仅是遍历,推荐增强for
有序,有存取顺序(元素顺序一致)
可以精确控制列表中每个元素的插入位置,可通过索引的方式访问/搜索元素
允许重复
方法名 | 返回值类型 | 说明 |
---|---|---|
add(int index,E element) | boolean | 在指定位置插入指定元素(原来位置的元素往后挪一个索引) 无位置则将指定的元素追加到此列表的末尾。 |
remove(int index)/(Object object) | E/boolean | 删除指定位置的元素,返回被删除的元素/删除指定元素 |
set(int index) | E | 修改指定位置的元素,返回被修改的元素 |
get(int index) | E | 获取指定位置的元素 |
小练习:
创建一个集合,有元素a,b,c,b,e
a,b,b,c,e
遍历这个集合,如果获取到元素b,将其删除
package api;
import java.util.ArrayList;
import java.util.Iterator;
public class CollectionDemo02 {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("b");
list.add("e");
for (int i = 0; i < list.size(); i++) {
if ("b".equals(list.get(i))){
list.remove("b");
}
}
System.out.println(list);
ArrayList list2 = new ArrayList<>();
list2.add("a");
list2.add("b");
list2.add("b");
list2.add("c");
list2.add("e");
for (int i = 0; i < list2.size(); i++) {
if ("b".equals(list2.get(i))){
list2.remove("b");
i--;
}
}
System.out.println(list2);
System.out.println("************************************************");
ArrayList list3 = new ArrayList<>();
list3.add("a");
list3.add("b");
list3.add("b");
list3.add("c");
list3.add("e");
Iterator iterator = list3.iterator();
while (iterator.hasNext()){
if ("b".equals(iterator.next())){
iterator.remove();
}
}
System.out.println(list3);
}
}
默认长度为10
自动扩容:创建一个1.5倍长度的数组,再将原数组复制到新数组中
底层是链表
主要方法
方法名 | 返回值类型 | 说明 |
---|---|---|
addFirst(E e) | 在列表开头插入元素 | |
addLast(E e) | 在列表结尾追加元素 | |
getFirst() | 返回列表第一个元素 | |
getLast() | 返回列表最后一个元素 | |
removeFirst() | 从此列表删除并返回第一个元素 | |
removeLast() | 从此列表删除并返回最后一个元素 |
主要特点:
去重
存取顺序不一致(如存ABC,取出来可能是CAB)
没有索引,故不能用普通for循环遍历,也不能通过索引来获取,删除Set集合里面的元素
package api;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set stringSet = new HashSet<>();
stringSet.add("a");
stringSet.add("b");
stringSet.add("v");
stringSet.add("d");
//遍历
Iterator iterator = stringSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("----------------------------------------------------");
for (String s : stringSet) {
System.out.println(s);
}
}
}
底层是红黑树
不包含重复元素
没有索引
可以将元素按照规则排序(注意这点:想要使用TreeSet,需要制定排序规则!)
①自然排序:
使用空参构造创建TreeSet集合
自定义的类实现Comparable接口
重写compareTo方法
@Override
public int compareTo(User o) {
//按年龄排序
int i = this.age - o.age;
return i;
}
自然排序简单原理
如果返回值为负数,表示当前存入的元素是较小值,放左边
如果返回值为0,表示元素重复,不存
如果返回值为正数,表示当前存入的元素是较大值,放右边
练习:创建一个TreeSet集合,存入5个User对象(有name,age就行),按照年龄排序,如果年龄相等,则按姓氏首字母排序
package api.practice02;
public class User implements Comparable{
private String username;
private String nickname;
private int age;
public User() {
}
public User(String username, String nickname, int age) {
this.username = username;
this.nickname = nickname;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", nickname='" + nickname + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(User o) {
int i = this.age - o.age;
if (i == 0){
i = this.username.compareTo(o.getUsername());
}
return i;
}
}
package api.practice02;
import java.util.TreeSet;
public class Application02 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet<>();
User user1 = new User("zhangsan","zhangsan",23);
User user2 = new User("zhangfei","zhangfei",26);
User user3 = new User("changyuan","changyuan",23);
User user4 = new User("zhangsan","zhangsan",46);
User user5 = new User("liusan","liusan",23);
treeSet.add(user1);
treeSet.add(user2);
treeSet.add(user3);
treeSet.add(user4);
treeSet.add(user5);
System.out.println(treeSet);
}
}
②比较器排序
TreeSet的带参构造使用的就是比较器排序
让集合构造方法接收Comparator的实现类对象,重写compare(to1,to2)方法
重写时排序规则必须按照要求的主要条件和次要条件来写
使用第二种方法做上个练习
package api.practice02;
import java.util.Comparator;
public class User2 {
private String username;
private String nickname;
private int age;
public User2() {
}
public User2(String username, String nickname, int age) {
this.username = username;
this.nickname = nickname;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", nickname='" + nickname + '\'' +
", age=" + age +
'}';
}
}
package api.practice02;
import java.util.Comparator;
import java.util.TreeSet;
public class Application02 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet<>(new Comparator() {
@Override
public int compare(User2 o1, User2 o2) {
//o1要存的数据:主要条件
//o2已经存入的:次要条件
int i = o1.getAge() - o2.getAge();
if (i == 0){
i = o1.getUsername().compareTo(o2.getUsername());
}
return i;
}
});
User2 user1 = new User2("zhangsan","zhangsan",23);
User2 user2 = new User2("zhangfei","zhangfei",26);
User2 user3 = new User2("changyuan","changyuan",23);
User2 user4 = new User2("zhangsan","zhangsan",46);
User2 user5 = new User2("liusan","liusan",23);
treeSet.add(user1);
treeSet.add(user2);
treeSet.add(user3);
treeSet.add(user4);
treeSet.add(user5);
System.out.println(treeSet);
}
}
在使用的时候,默认使用自然排序,如果自然排序不满足需求时,改为比较器排序,两种方法返回值的规则是一样的
存取顺序不一致
没有索引,不能普通for
元素不重复(唯一)
哈希值:哈希码值
JDK根据对象的地址或者属性值,算出来的int类型的整数
Object类有hashCode方法用来获取对象的哈希值,可重写,重写后默认是对象的属性值比较
####
注意:如果HashSet集合要存储自定义对象,自定义类必须重写equals和hashCode
练习:
创建一个存储用户对象的集合,存储多个User对象,使用程序实现在控制台遍历该集合要求:User对象的成员变量值相同,我们就认为是同一个对象,不储存
重写equals和hashCode就行
User user1 = new User("张三","Z",35);
User user2 = new User("李四","L",39);
User user3 = new User("张三","Z",35);
//自己写吧~
Interface Map
如 身份证,具体的人
方法名 | 返回值类型 | 说明 |
---|---|---|
put(K,V) | V | 不存在则添加元素,如果键值存在,则替换并返回被替换的值 |
remove(Object) | V | 根据键值删除对应元素,返回被删除的值 |
clear | void | 清空 |
containsKey | boolean | 判断是否包含指定键值 |
containsValue | boolean | 判断是否包含指定值 |
isEmpty | boolean | 判断是否为空 |
size | int | 集合长度,键值对的个数 |
keySet() | Set< K > | 获取所有键 |
get(k) | V | 根据键值获取值 |
Set |
获取所有键值对对象 |
package api;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
Map map = new HashMap<>();
map.put("a", "aa");
map.put("b", "bb");
map.put("c", "cc");
map.put("d", "dd");
final Set stringSet = map.keySet();
for (String s : stringSet) {
System.out.println(s + ":" + map.get(s));
}
System.out.println("--------------------------------------------");
//键值对
final Set> entries = map.entrySet();
for (Map.Entry entry : entries) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
底层是哈希表
Map的一个实现类
无特有方法
底层是哈希表
依赖equals方法和hashCode方法保证键的唯一性
如果键要存储自定义对象,需要重写equals和hashCode方法
HashMap集合存储自定义对象并遍历
键是User对象,值随便写
package api.practice02;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Application05 {
public static void main(String[] args) {
User user1 = new User("张三","Z",35);
User user2 = new User("李四","L",39);
User user3 = new User("张三","Z",36);
HashMap userHashMap = new HashMap<>(16);
userHashMap.put(user1,1000012L);
userHashMap.put(user2,1000054L);
userHashMap.put(user3,1000125L);
//第一种
final Set> entries = userHashMap.entrySet();
for (Map.Entry entry : entries) {
System.out.println(entry.getKey()+",id:"+entry.getValue());
}
//第二种
final Set users = userHashMap.keySet();
for (User user : users) {
System.out.println(user+",id:"+userHashMap.get(user));
}
//第三种,lambda
userHashMap.forEach(
(User user,Long l) -> {
System.out.println(user+",id:"+l);
}
);
}
}
Map的一个实现类
无特有方法
底层是红黑树
排序只排序键,不排序值(自然或比较器排序)
如果键存储的是自定义对象,需要实现Comparable接口或者在创建treeMap对象时给出比较器排序规则
HashMap集合存储自定义对象,排序并遍历
键是User对象,值随便写,按照年龄排序
package api.practice02;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Application06 {
public static void main(String[] args) {
TreeMap userTreeMap = new TreeMap<>();
User user1 = new User("张三","Z",35);
User user2 = new User("李四","L",39);
User user3 = new User("张三","Z",36);
userTreeMap.put(user1,1000012L);
userTreeMap.put(user2,1000016L);
userTreeMap.put(user3,1000082L);
final Set users = userTreeMap.keySet();
for (User user : users) {
System.out.println(user+",id:"+userTreeMap.get(user));
}
System.out.println("---------------------------------------------");
final Set> entries = userTreeMap.entrySet();
for (Map.Entry entry : entries) {
System.out.println(entry.getKey()+",id:"+entry.getValue());
}
System.out.println("==================================================");
userTreeMap.forEach(
(User u,Long l) ->{
System.out.println(u+",id:"+l);
}
);
}
}
简单来看就是子弹(数据)和弹夹(栈)
简单来看就是排队
在树结构中,每一个元素称为节点(也就是对象)
其构成
又称二叉排序树或二叉搜索树,查找效率相对于二叉树高许多
其特点:
每一个节点最多有两个子节点(二叉树)
左子树上所有节点的值都小于根节点的值
右子树上所有节点的值都大于根节点的值
二插查找树添加节点规则:
小的在左
大的在右
一样不存
添加的第一个元素作为根节点,之后的元素与根节点的值比较判断在左还是在右,小左大右
如果左右子节点都已存在数值,则将插入元素在与子节点的值比较,规则还是小左大右
普通二叉树或二叉搜索树都可能导致左右子树不平衡,如左/右子树过于庞大导致不对称
为了优化这一问题,平衡二叉树闪亮登场~
平衡二叉树特点
二叉树左右两个子树的高度差不大于1
任意节点的左右两个子树都是一棵平衡二叉树
平衡二叉树的旋转机制
右旋:就是将根节点的左侧往右拉,原先的左子节点变为新的父节点,并把多余的右子节点让出,给已经降级的根节点当左子节点
图同左旋,不放图了
旋转的四种情况:
左左:当根节点左子树的左子树有节点插入,导致二叉树不平衡(整体右旋)
左右:当根节点左子树的右子树有节点插入,导致二叉树不平衡(区域左旋,变为左左的情况)
一种特殊的二叉查找树,红黑树上的每一个节点都有存储位表示节点的颜色,每一个节点可以是红或者黑
红黑树不是高度平衡的,它的平衡根据“红黑规则”进行实现
红黑规则
每一个节点都是红或黑
根节点必须是黑色
如果一个节点没有子节点或父节点,则该节点相应的指针属性值为Nil(null),这些Nil视为叶节点,叶节点都是很色的
如果某一个节点是红色的,那么它的子节点必须是黑色的(红色节点不能相连)
对每一个节点,从该节点到其所有后代节点的简单路径(单向:从上到下)上,均包含相同数量的黑色节点
添加节点
添加的节点默认是红色
继续添加元素
JDK8以前(不包括JDK8):底层是数组(默认长度16,加载因子0.75)+链表
首先会先获取元素的哈希值,计算出在数组中应存入的索引判断该索引处是否为null
如果是null,直接添加,如果不是null,则与链表中所有的元素,通过equals方法比较属性值,只要有一个相同,就不存,如果都不一样,才会存入集合
加载因子:当数组存了16*加载因子时,数组会扩容
JDK8以后(包括JDK8):底层优化,数组+链表+红黑树
JDK5新特性,提供了编译时类型安全检测机制
把运行时期的问题提前到编译器
避免强制类型转换
前面写过
n数求和
package api.practice02;
public class Application07 {
public static void main(String[] args) {
final int sum = sum(1, 2, 3, 4, 5, 6, 7, 8);
System.out.println(sum);
}
public static int sum(int... nums){
int sum = 0;
for (int n:nums) {
sum += n;
}
return sum;
}
}
方法名(静态方法) | 返回值类型 | 说明 |
---|---|---|
List.of(元素) | 创建一个具有指定元素的List集合对象 | |
Set.of(元素) | 创建一个具有指定元素的Set集合对象 | |
Map.of(元素) | 创建一个具有指定元素的Map集合对象 | |
Map.ofEntries(Map.entry) | 简化Map.of |
拓展小知识,也可能用不上:IDEA更换JDK版本
下载并配置的jdk8,用不了of怎么办,网上下载一个jdk11,IDEA更改一下就行~
package api.practice02;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Application08 {
public static void main(String[] args) {
//1.集合的批量添加
//首先是通过List.of创建一个不可变集合,
//在创建一个ArrayList集合,并把这个不可变集合中的所有数据都添加到ArrayList集合中
ArrayList arrayList = new ArrayList(List.of("a","b","v","d"));
Set.of("注意元素不要重复就行");
Map.of("键","键值","键02","键值02");
//简化Map.of
Map.Entry entry1 = Map.entry("K", "V");
Map.Entry entry2 = Map.entry("K", "V");
Map.ofEntries(entry1,entry2);
}
}
开始时间2023-12-12-0:0:0,
结束时间2023-12-12-0:30:0
客户A下单并付款时间:2023-12-12-0:13:0
客户B下单并付款时间:2023-12-12-0:32:0
判断两位客户有没有参加上该秒杀活动?
package api;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateDemo02 {
public static void main(String[] args) throws ParseException {
String start = "2023-12-12 0:0:0";
String end = "2023-12-12 0:30:0";
String clientA = "2023-12-12 0:13:0";
String clientB = "2023-12-12 0:32:0";
DateDemo02 dateDemo02 = new DateDemo02();
long[] rule = dateDemo02.startTimeEndTime(dateDemo02.dateParse(start), dateDemo02.dateParse(end) );
String judgeA = dateDemo02.judge(rule, dateDemo02.dateParse(clientA));
System.out.println("A"+judgeA);
String judgeB = dateDemo02.judge(rule, dateDemo02.dateParse(clientB));
System.out.println("B"+judgeB);
}
/**
* 判断是否参加了秒杀活动
* @param rule 限制
* @param time 时间
* @return 是否参加了活动
*/
public String judge(long[] rule,long time){
if (time < rule[0] || time > rule[1]){
return "该用户未能参加秒杀活动";
}
return "该用户参加了秒杀活动";
}
/**
* 获得活动时间区间
* @param start 开始时间
* @param end 结束时间
* @return 活动时间区
*/
public long[] startTimeEndTime(long start, long end){
long[] sectionTime = new long[2];
sectionTime[0] = start;
sectionTime[1] = end;
return sectionTime;
}
/**
* 日期解析方法
* @param date
* @return
*/
public long dateParse(String date){
long time = 0;
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
time = simpleDateFormat.parse(date).getTime();
} catch (ParseException e) {
System.out.println("解析出错了,请检查日期格式是否正确");
}
return time;
}
}
创建一个User对象,三个属性username,nickname和age
用Collection存储三个User对象,并遍历
package api.practice02;
public class User {
private String username;
private String nickname;
private int age;
public User() {
}
public User(String username, String nickname, int age) {
this.username = username;
this.nickname = nickname;
this.age = age;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package api.practice02;
import java.util.ArrayList;
import java.util.Collection;
public class Application {
public static void main(String[] args) {
User user1 = new User("张三","Z",35);
User user2 = new User("李四","L",39);
User user3 = new User("王五","W",25);
ArrayList list = new ArrayList<>();
list.add(user1);
list.add(user2);
list.add(user3);
for (User user : list) {
System.out.println(user.getUsername()+","+user.getNickname()+","+user.getAge());
}
//迭代器方式
Iterator iterator = list.iterator();
while (iterator.hasNext()){
User user = iterator.next();
System.out.println(user.toString());
}
}
}
package api.practice02;
import java.util.Comparator;
import java.util.TreeSet;
public class Application03 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet<>(new Comparator() {
@Override
public int compare(String o1, String o2) {
int i = o1.length() - o2.length();
i = i == 0 ? o1.compareTo(o2):i;
return i;
}
});
//“a”,“ab”,“ac”,“abc”,“bac”
treeSet.add("a");
treeSet.add("ab");
treeSet.add("ac");
treeSet.add("abc");
treeSet.add("bac");
System.out.println(treeSet);
}
}