JAVA API学习笔记
文章目录
- [JAVA API学习笔记](#JAVA API学习笔记)
-
- 一、基础概念
-
- [1.1 API概念说明](#1.1 API概念说明)
- 二、工具类
-
- [2.1 Math](#2.1 Math)
- [2.2 System](#2.2 System)
- [2.3 Objects](#2.3 Objects)
- [2.4 Runtime](#2.4 Runtime)
- 三、字符串相关类
-
- [3.1 String](#3.1 String)
- [3.2 StringBuilder](#3.2 StringBuilder)
- [3.3 StringJoiner](#3.3 StringJoiner)
- [3.4 字符串综合练习](#3.4 字符串综合练习)
- [四、包装类 & 大数类 & Object根父类](#四、包装类 & 大数类 & Object根父类)
-
- [4.1 Integer](#4.1 Integer)
- [4.2 BigInteger](#4.2 BigInteger)
- [4.3 BigDecimal](#4.3 BigDecimal)
- [4.4 Object](#4.4 Object)
- 五、时间API
-
- [5.1 JDK7 旧时间API](#5.1 JDK7 旧时间API)
-
- 5.1.1Date
- [5.1.2 SimpleDateFormat](#5.1.2 SimpleDateFormat)
- [5.1.3 Calendar](#5.1.3 Calendar)
- [5.2 JDK8 java.time 新时间API](#5.2 JDK8 java.time 新时间API)
-
- [5.2.1 时间对象](#5.2.1 时间对象)
- [5.2.2 格式化类 DateTimeFormatter](#5.2.2 格式化类 DateTimeFormatter)
- [5.2.3 时间间隔工具类](#5.2.3 时间间隔工具类)
一、基础概念
1.1 API概念说明
核心概念:API = JDK 提供的所有类、接口;工具类是 API 中的一类
分成 4 大模块:工具类、字符串相关、包装 & 大数 & 根父类、时间 API(旧 + 新),结构清晰方便复习。
二、工具类
描述:
- 构造方法私有,不能 new 创建对象
- 全部静态,直接
类名.方法()调用
2.1 Math
| 静态方法 | 作用 |
|---|---|
public static int abs(int a) |
获取参数绝对值 |
public static double ceil(double a) |
向上取整 |
public static double floor(double a) |
向下取整 |
public static int round(float a) |
四舍五入 |
public static int max(int a,int b) |
获取两个 int 最大值 |
public static double pow(double a , double b) |
返回 a 的 b 次幂 |
public static double random() |
返回[0.0,1.0)随机小数 |
public static double sqrt(double a) |
返回平方根 |
public static double cbrt(double a) |
返回立方根 |
Java
int a = 10;
int b = 20;
//加法
System.out.println(a+b); // 30
//减法
System.out.println(a-b); // -10
//乘法
System.out.println(a*b); // 200
//除法
System.out.println(a/b); // 0
//取模
System.out.println(a%b); // 10
//取绝对值
System.out.println(Math.abs(a)); // 10
//向上取整
System.out.println(Math.ceil(1.1)); // 2.0
//向下取整
System.out.println(Math.floor(1.9)); // 1.0
//四舍五入
System.out.println(Math.round(1.5)); // 2
//获取两个数中较大的值
System.out.println(Math.max(a, b)); // 20
//获取a的b次幂
System.out.println(Math.pow(2, 3)); // 8.0
//获取随机数
System.out.println(Math.random()); // 0.0 ~ 1.0
//获取一个数的平方根
System.out.println(Math.sqrt(4)); // 2.0
//获取一个数的立方根
System.out.println(Math.cbrt(8)); // 2.0
2.2 System
描述:
1:也是一个工具类 提供了一些关于系统的方法
2:时间原点:1970年1月1日0.00 我国在东八区 有八小时误差
3.一秒= 1000毫秒
exit
- public static void exit(int status) // 状态码0表示正常关闭 非0当前虚拟机异常退出 终止当前虚拟机
java
public static void main(String[] args) {
//关闭虚拟机 (状态码0表示正常关闭 非0当前虚拟机异常退出)
System.exit(0); // 关闭虚拟机
System.out.println("看看我执行了吗?");//并没有执行
currentTimeMillis
- public static long currenttimemills; // 获取当前时间的毫秒值
java
long startTime = System.currentTimeMillis();
int count = 100;
while (count > 0) {
System.out.println("虚拟机运行中..." + count);
count--;
}
long endTime = System.currentTimeMillis();
System.out.println("虚拟机运行时间:" + (endTime - startTime) + "毫秒");
arraycopy
- public static void arraycopy(数据源数组,起始位置,目标数组,起始位置,复制的个数)
java
int arr1[] = {1, 2, 3, 4, 5};
int arr2[] = new int[5];
System.arraycopy(arr1, 0, arr2, 0, 5);
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + " ");//1 2 3 4 5
}
System.out.println();
- 如果数据源数组和目标数组都是基本数据类型 那么两个数组的类型要保持一致 否则会报错
- 再拷贝的时候需要考虑数组长度,超出数组则会报错
- 如果数据源数组和目标数组是引用数据类型,那么子类数组可以拷贝给父类数组
Java
student s1 = new student("张三", 18);
student s2 = new student("李四", 20);
student s3 = new student("王五", 22);
student [] arr = {s1, s2, s3};
father [] arr2 = new father[3];
System.arraycopy(arr, 0, arr2, 0, arr.length);
for (int i = 0; i < arr.length; i++) {
student s = (student) arr2[i];
System.out.println(s.name + " " + s.age);
}
2.3 Objects
equal
先判断是否为空 在进行比较
Java
//1.底层逻辑会先判断s1是不是为空 如果s1为空则会返回false
//2.如果s1不为空就会使用equals进行比较没有重写方法则会比较地址值 重写了则会比较属性值
int [] arr = {1,2,3,4,5};
Student s1 = new Student("张三", 18, "男", arr);
Student s2 = new Student("张三", 18, "男", arr);
boolean flag = Objects.equals(s1, s2);
System.out.println(flag);//true
isnull
nonull
java
//判断s1是否为空
boolean flag2 = Objects.isNull(s1);
System.out.println(flag2); // false
//判断s1是否不为空
boolean flag3 = Objects.nonNull(s1);
System.out.println(flag3); // true
2.4 Runtime
描述 :表示当前虚拟机的状态 Runtime 代表 Java 程序的运行时环境,不能 new 对象,通过getRuntime()获取实例
getRuntime()
- public static Runtime getRuntime(); 获取当前系统的运行对象
java
Runtime runtime = Runtime.getRuntime();
exit
- public void exit(0) 停止虚拟机
java
Runtime runtime = Runtime.getRuntime();
runtime.exit(0);
System.out.println("看看我执行了吗");//并没有执行 system.exit(0);用的底层代码就是runtime.exit(0);
availableprocessors
- public int availableProcessors() 获取CPU可用处理器(线程)数量
maxMemory
- public long maxMemory() JVM最大可从系统申请的内存,单位字节(byte)
totalMemory
- public long totalMemory() JVM当前已经向系统申请到的内存,单位字节(byte)
freeMemory
- public long freeMemory() JVM当前空闲可用内存,单位字节(byte)
java
Runtime runtime = Runtime.getRuntime();
//获取cpu的线程数
System.out.println("Available processors: " + runtime.availableProcessors());
//获取jvm已经从系统中获取的总内存
System.out.println("Total memory: " + runtime.totalMemory()/1024/1024);//126MB
//获取jvm剩余空闲内存大小
System.out.println("Free memory: " + runtime.freeMemory()/1024/1024);//122MB
//获取jvm能从系统中获取的最大内存
System.out.println("Max memory: " + runtime.maxMemory()/1024/1024);//1998MB
exec
- public Process exec(String command) 执行操作系统cmd/shell命令,返回进程对象Process
**shutdown : 关机 **
加上参数才能执行 -s: 默认一分钟之后关机
-s -t 指定时间:指定关机时间
-a :取消关机操作
-r :关机并重启
java
Runtime runtime = Runtime.getRuntime();
System.out.println(runtime.exec("shutdown -s -t 3600"));
}//一小时后关机
三、字符串相关类
3.1 String
介绍:
- String是Java定义好的一个类。定义在Java.lang包中,使用的时候不需要到导包。
- Java程序中的所有字符串文字(例如"abc")都是此类的对象
- 字符串不可变,他们的值在创建后不能被更改
创建String对象的方式
1.直接赋值
Java
//1.直接赋值字符串
String S1 = "Hello";
System.out.println(S1);//Hello
2.构造方法
public string() 空白字符串 不含任何内容。
public String (字符串) 根据传入的字符串,创建新的字符串对象
public String (char\[\] chs) 根据字符数组,创建字符串对象
public String(byte\[\] chs) 根据字节数组,创建字符串对象
java
//1.通过new关键字
String S2 = new String("Hello");
System.out.println(S2);//Hello
//2.空白字符串,不含有任何字符
String S3 = new String();
System.out.println(S3);//""
//3.通过字符数组赋值
char[] ch = {'H','e','l','l','o'};
String S4 = new String(ch);
System.out.println(S4);//Hello
//4.通过字节数组赋值
byte[] b = {72,101,108,108,111};
String S5 = new String(b);
System.out.println(S5);//Hello ACSLL表 72----"H"
}
两种创建方式的区别
直接赋值会复用串池里面的内同 new出来的都是一个新的地址
-
String. equals(Object anObject) 比较两个字符串的内容,注意不能为null。
-
equalsIgnoreCase(String anotherString) 与equals方法相似,但忽略大小写。
java
public static void main(String[] args) {
//已知正确账号和密码,请用程序模拟登录系统
// 一共有三次机会,登录之后会有相应的提示
String rightnumber = "lisi"; // 已知正确账号
String rightpassword = "123456"; // 已知正确密码
//2.键盘输入账号和密码
Scanner scanner = new Scanner(System.in);
//3.循环输入账号和密码,判断是否正确
for (int i = 1; i <= 3; i++) {
System.out.println("请输入账号:");
String number = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
if (number.equals(rightnumber) && password.equals(rightpassword)) {
System.out.println("登录成功!");
break;
} else {
if (i == 3){
System.out.println("账号或密码错误!您已输入错误3次,账号已锁定!");
}else {
System.out.println("账号或密码错误!还剩" + (3 - i) + "次机会");
}
}
}
substring
截取字符串:substring(0,3);//截取字符串,包左不包右 (开始索引,结束索引)
substring(6);//截取字符串,直接到末尾
字符串本身一旦创建之后,是无法发生改变的。截取时候不会影响调用者的字符串,切记:只有返回值才是截取之后的结果
Java
public static void main(String[] args) {
String str1 = "Hello, World!";
String result = str1.substring(0, 5);
System.out.println(result);//Hello
String str2 = str1 .substring(1);
System.out.println(str2);//ello, World!
}
Replace
替换 :String replace(旧值,新值)
注意点:只有返回值才是替换后的结果
JAVA
public static void main(String[] args) {
String str = "你好菜呀,TMD!";
str = str.replace("TMD", "***");
System.out.println(str);//你好菜呀,***!
}
}
Contains
字符串包含判断 contains("是否包含的字符")
Java
String str = "abcd";
boolean flag = str.contains("abc");
System.out.println(flag);//true
startsWith()/ endsWith()
判断开头 startsWith("字符") 判断是不是以字符开头
判断结尾 endsWith(("字符")判断是不是以字符结尾
Java
String str = "abcd";
//判断开头 startsWith()
boolean flag2 = str.startsWith("ab");
System.out.println(flag2);//true
//判断结尾 endsWith()
boolean flag3 = str.endsWith("cd");
System.out.println(flag3);//true
indexOf()
查找子字符串 indexOf() 查找指定字符第一次出现的位置
java
String str = "abcd";
//查找子字符串 indexOf() 查找指定字符第一次出现的位置
int index = str.indexOf("bc");
System.out.println(index);//1
isEmpty()
判断字符串是否为空 isEmpty()
java
String str = "abcd";
boolean flag4 = str.isEmpty();
System.out.println(flag4);//false
toUpperCase()/toLowerCase()
转换为大写/转换为小写
java
String str = "abcd";
//转换为大写 toUpperCase()
String str2 = str.toUpperCase();
System.out.println(str2);//ABCD
//转换为小写 toLowerCase()
String str3 = str.toLowerCase();
System.out.println(str3);//abcd
toCharArray()
转为字符数组
java
char[] charArray = str.toCharArray();
for (char c : charArray) {
System.out.println(c);
}//abcd
trim
去除头尾空格
java
String str4 = " abcd ";
String str5 = str4.trim();
System.out.println(str5);//abcd
3.2 StringBuilder
构造方法:带参构造/无参构造
Java
StringBuilder sb = new StringBuilder();
System.out.println(sb);//[]
StringBuilder sb2 = new StringBuilder("abc");
System.out.println(sb2);//[abc]
append
JAVA
StringBuilder sb = new StringBuilder();
System.out.println(sb);//[]
sb.append("Hello");
System.out.println(sb);//[Hello]
reverse
sb.reverse();反转容器里面的内容
java
sb.reverse();
System.out.println(sb);//[olleH]
toString()
sb.toString();把String容器转换为String
java
String str = sb.toString();
System.out.println(str);//olleH
3.3 StringJoiner
StringJoiner sj = new StringJoiner("," ,"", "");//间隔符号,开始符号,结束符号 创建一个Stringjoiner容器
add("ccc");//添加元素,只能添加字符串 跟Stringbulid 不同
sj.length();//获取容器长度
sj.toString()//转化为字符串
3.4 字符串综合练习
JAVA
public static void main(String[] args) {
int arr[] = {1, 2, 3, 4, 5};
System.out.println(getString(arr));//[1, 2, 3, 4, 5]
}
public static String getString(int [] arr) {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);
if (i != arr.length - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
}
1.打印数组
JAVA
public static void main(String[] args) {
int arr[] = {1, 2, 3, 4, 5};
System.out.println(getString(arr));//[1, 2, 3, 4, 5]
}
public static String getString(int [] arr) {
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arr.length; i++) {
sb.append(arr[i]);
if (i != arr.length - 1) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
}
2.统计字符字数
java
package oop01;
import java.util.Scanner;
public class StringDemo01 {
public static void main(String[] args) {
//
// 作业2:写出一个程序,接受一个由数字空格字母组成的字符串,和一个字符,统计这个字符在字符串中出现的次数。
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个由数字空格字母组成的字符串");
String str = sc.nextLine();
System.out.println("请输入一个字符");
char ch = getchar(sc);
int count = getCount(str, ch);
System.out.println("字符" + ch + "在字符串中出现的次数为:" + count);
}
//定义一个方法,统计字符在字符串中出现的次数,不区分大小写
private static int getCount(String str, char ch) {
int count = 0;
ch = Character.toLowerCase(ch);
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == ch) {
count++;
}
}
return count;
}
//定义一个方法验证输入的字符是否合法,如果输入的字符是空格,则重新输入
private static char getchar(Scanner sc) {
while (true){
char ch = sc.next().charAt(0);
if (ch!=' '){
return ch;
}
System.out.println("输入错误,请重新输入");
}
}
}
3.返回字符串长度
java
import java.util.Scanner;
public class StringDemo03 {
//作业3:写出一个程序,接受一个字符串,返回字符串中最后一个字符的长度。
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = sc.next();
int getcount = getcount(str);
System.out.println("字符串中最后一个字符长度为:" + getcount);
}
private static int getcount(String str) {
//去除头尾空格
str = str.trim();
//判断字符串是否为空
if (str.isEmpty()){
return 0;
}
//找到最后一个空格的位置
int count = str.lastIndexOf(' ');
return str.length()-count -1;
}
}
4.身份证号返回年月日
java
//作业4:写出一个程序,接受一个身份证号码,返回出生年月日和性别。
public static void main(String[] args) {
String personpassword = "11010119980515234X";
StringBuilder sb = new StringBuilder(personpassword);
String year = sb.substring(6,10);
String month = sb.substring(10,12);
String day = sb.substring(12,14);
System.out.println("出生年月日为:" + year + "年" + month + "月" + day + "日");
char sex = sb.charAt(16);
System.out.println("性别为:" + (sex % 2 == 0 ? "女" : "男"));
}
}
5.整数前后加
java
//将一个字符串中所有的整数前后加上符号"*",其他字符保持不变,连续的数字视为一个整
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = "3fda23";
StringBuilder sb = new StringBuilder(str);
if (sb.length() > 0 && sb.charAt(sb.length() - 1) >= '0' && sb.charAt(sb.length() - 1) <= '9') {
sb.append('*');
}
for (int i = sb.length()-1; i > 0; i--) {
char c = sb.charAt(i);
char test = sb.charAt(i-1);
if (c == '*') {
continue;
}
if (c >= '0' && c <= '9' && (test < '0' || test > '9')||((test >= '0' && test <= '9' )&& (c < '0' || c > '9'))) {
sb.insert(i, '*');
}
}
if (sb.length() > 0 && sb.charAt(0) >= '0' && sb.charAt(0) <= '9') {
sb.insert(0, '*');
}
System.out.println(sb.toString());
}
6.获取验证码
java
public static void main(String[] args) {
//获取一个验证码,验证码由4个大写字母和1个数字组成,且数字可以是任意位置
System.out.println(getCode());
}
public static String getCode() {
// 创建一个包含所有字母的数组
char [] arr = new char[52];
// 填充大写字母
for (int i = 0; i < arr.length/2; i++) {
arr[i] = (char)('A' + i);
}
// 填充小写字母
for (int i = arr.length/2; i < arr.length; i++) {
arr[i] = (char)('a' + i-26);
}
// 打印数组
// 创建一个StringBuilder对象
StringBuilder sb = new StringBuilder();
// 随机获取4个字符并添加到StringBuilder中
for (int i = 0; i < 4; i++) {
int index = (int)(Math.random() * arr.length);
sb.append(arr[index]);
// 随机获取一个数字并添加到StringBuilder中
}
int num = (int)(Math.random() * 10);
sb.append(num);
char[] ch = sb.toString().toCharArray();
int index = (int)(Math.random() * ch.length);
char temp = ch[ch.length - 1];
ch[ch.length - 1] = ch[index];
ch[index] = temp;
return new String(ch);
}
四、包装类 & 大数类 & Object根父类
4.1 Integer
***获取intger的方法:***构造方法 静态方法 直接赋值
- 构造方法
java
// 创建Integer对象
//创建新的对象
// 使用new关键字创建对象 每次都会在内存中创建新的对象
Integer i = new Integer(13); // 自版本9起已弃用
Integer i1 = new Integer(13);
System.out.println(i==i1);//false
2.静态方法
Java
// 使用valueOf方法创建对象 会使用缓存中的对象
// 会先从缓存中查找,如果找到则返回缓存中的对象,如果找不到则创建新的对象
// 也就是包装类常量池 范围为 -128~127 找不到则会使用new关键字创建新的对象
Integer i2 = Integer.valueOf(127);
Integer i3 = Integer.valueOf(127);
System.out.println(i2==i3);//true
Integer i4 = Integer.valueOf(128);
Integer i5 = Integer.valueOf(128);
System.out.println(i4==i5);//false
- 直接赋值
Java
//直接赋值 会使用缓存中的对象 valueOf方法简化版
Integer i6 = 127;
Integer i7 = 127;
System.out.println(i6==i7);//true
4.2 BigInteger
java中的大整数
获取方式只有两种 不能直接赋值
Java
//1.利用构造方法创建对象
BigInteger bd1 = new BigInteger("10");
BigInteger bd2 = new BigInteger("10");
System.out.println(bd1==bd2) ; // false
//2.利用valueOf方法创建对象 跟integer一样 会有一个缓存区 也就是常量池 范围为(-16到16)一共为33个
//细节:valueOf方法会检查缓存区,如果缓存区中存在该对象,则返回缓存区中的对象,否则返回新创建的对象
//如果获取的数字比较大 超出了long的范围,此时只能用构造方法获取数据
BigInteger bd3 = BigInteger.valueOf(16);
BigInteger bd4 = BigInteger.valueOf(16);
System.out.println(bd3==bd4); // true
BigInteger bd5 = BigInteger.valueOf(17);
BigInteger bd6 = BigInteger.valueOf(17);
System.out.println(bd5==bd6); // false
//3.不能直接赋值,否则会报错
成员方法
进行计算 不会影响原来的值 而是会创建一个新的对象
Java
public static void main(String[] args) {
BigInteger b1 = new BigInteger("10");
BigInteger b2 = new BigInteger("20");
//加法
System.out.println(b1.add(b2)); // 30
//减法
System.out.println(b1.subtract(b2)); // -10
//乘法
System.out.println(b1.multiply(b2)); // 200
//除法 取商
System.out.println(b2.divide(b1)); // 2
//除法 取商还有余数 返回数组
BigInteger[] bigIntegers = b2.divideAndRemainder(b1);// [2, 0]
System.out.println(bigIntegers[0]); // 2
System.out.println(bigIntegers[1]); // 0
//取模
System.out.println(b2.mod(b1)); // 0
//取余
System.out.println(b2.remainder(b1)); // 0
//取最大值
BigInteger max = b2.max(b1);// 20
//把最大值b2的地址值赋值给max,max和b2指向同一个对象
System.out.println(max); // 20
//次方
System.out.println(b2.pow(2)); // 400
4.3 BigDecimal
作用: 用来表示较大的小数 和解决小数不精确的问题
java
public static void main(String[] args) {
//1. 利用构造方法 创建一个BigDecimal对象
//创建数组 传递数组
char [] ch = { '1', '2', '3' };
BigDecimal b1 = new BigDecimal(ch);
System.out.println(b1);
// 传递字符串
BigDecimal b2 = new BigDecimal("123");
System.out.println(b2); // 123
// 传递double 会报错 因为double是浮点数 会存在精度问题
BigDecimal b3 = new BigDecimal(1.123);
System.out.println(b3);
//2.利用静态方法创建BigDecimal对象
// 优化机制 会有一个常量池 {0 -10}
BigDecimal b4 = BigDecimal.valueOf(1.123);
System.out.println(b4);//1.123
BigDecimal b5 = BigDecimal.valueOf(10);
BigDecimal b6 = BigDecimal.valueOf(10);
System.out.println(b5==b6);//true
BigDecimal b7 = BigDecimal.valueOf(11);
BigDecimal b8 = BigDecimal.valueOf(11);
System.out.println(b7==b8);//false
//结论:如果在double范围使用静态方法获取对象 超出double范围使用构造方法 (参数必须以字符串形式)
//常见方法 加减乘除
BigDecimal b9 = new BigDecimal("30");
BigDecimal b10 = new BigDecimal("100");
System.out.println(b9.add(b10)); // 130
System.out.println(b10.subtract(b9)); // 70
System.out.println(b9.multiply(b10)); // 3000
System.out.println(b10.divide(b9)); // 3.3333333333333335 (无限循环) 会报错 因为BigDecimal默认是精确计算的,不允许有余数
// 取商和余数
BigDecimal [] arr = b10.divideAndRemainder(b9);
System.out.println(arr[0]); // 3
System.out.println(arr[1]); // 10
// 保留小数位数 四舍五入
System.out.println(b10.divide(b9, 2, BigDecimal.ROUND_HALF_UP)); // 3.33
}
}
4.4 Object
所以子类共同的父类
toString
1.返回对象的字符串表示形式
2.当我们打印一个对象的时候,底层会调用对象的toString方法,把对象变成字符串然后再打印在控制台上,打印完毕换行处理
3.默认打印的是地址值,但对于我们是没有意义的,如果我们想看到对象内部的属性值,重写toString方法就可以了
toString 重写位置:自己定义的 Javabean 实体类当中,使用 Alt+Insert 自动生成。
Object 提供原始 toString,返回地址;子类重写,返回对象的属性信息。
Java
public class student {
String name;
int age;
String sex;
public student() {
}
public student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
Java
public static void main(String[] args) throws IOException {
student a = new student("张三", 18, "男");
System.out.println(a.toString());//heima.com.ui.student@2f4d3709 重写前
System.out.println(a);//student{name='张三', age=18, sex='男'} 重写后
}
equals
1.如果没有重写equals方法,那么默认使用object中的方法进行比较,比较的是地址值
2,一般来讲比较地址值对于我们意义不大,所以我们会进行重写,重写之后比较的就是对象内部的属性值了
Java
public class student {
String name;
int age;
String sex;
public student() {
}
public student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
student student = (student) o;
return age == student.age && Objects.equals(name, student.name) && Objects.equals(sex, student.sex);
}
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
}
Java
public static void main(String[] args) throws IOException {
student a = new student("张三", 18, "男");
student b = new student("张三", 18, "男");
System.out.println(a == b);//false (重写前比较的是地址值)
System.out.println(a.equals(b));//true (重写后比较的是对象内部的属性值)
}
拓展
Java
public static void main(String[] args) throws IOException {
String s = "hello";
StringBuilder sb = new StringBuilder("hello");
System.out.println(s.equals(sb));//false
System.out.println(sb.equals(s));//false
}
}
equals 笔记总结
- Object 的 equals(StringBuilder 直接使用,没有重写)
- 只做一件事:比较对象地址
- 地址相同返回 true,不同直接返回 false,没有后续逻辑。
- StringBuilder 没有重写 equals,所以比较的是地址,不比较字符内容。
-
String 重写后的 equals 【源码真实执行顺序】
-
第一步:
this == anObject判断地址- 如果是同一个对象,地址相同 → 直接返回 true,后面代码不执行。
-
地址不一样,才执行第二步:
instanceof判断是不是 String 类型- 如果不是 String 类型,直接返回 false。
- 如果是 String,再逐个比较内部每一个字符。
-
字符全部相同返回 true,否则返回 false。
源码顺序:先比地址 → 再判断类型 → 最后比较字符
- 区分口诀
==:永远比较地址。- String.equals:先比地址,地址相同直接 true;地址不同,判断类型,再比内容。
- StringBuilder.equals:等价
==,只比较对象地址,不比较内容。
注意:部分视频讲课会口头先说类型判断,是为突出考点,以 JDK 源码的代码行顺序为准。
Clone
1.重写object类的clone方法
Java
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
2.让JavaBean实现Cloneable接口
Java
public class Student implements Cloneable {
String name;
int [] arr;
int age;
String sex;
public Student() {
}
3,创建原对象并调用clone就可以了
浅克隆
不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来
Java
public static void main(String[] args) throws IOException, CloneNotSupportedException {
// 测试克隆
//1.先创建一个对象
int [] arr = {1,2,3,4,5};
Student s1 = new Student("张三", 18, "男", arr);
//2.克隆对象
// 底层会帮我们创建对象,调用的是Object类中的clone方法 并将源对象的内容拷贝过去
// 步骤 1. 先重写object的clone方法
// 2. 让Javabean源对象实现Cloneable接口
// 3. 创建原对象调用clone方法即可
Student s2 = (Student) s1.clone();
//验证object里的clone是不是浅克隆 这里已经克隆完成 现在修改s1中的数组 查看s2是否受到影响
int [] data = s1.arr;
data[0] = 100;
//输出s1和s2 结果为浅克隆 s1 中的基本数据类型和字符串是独立的,但引用数据类型是共享的
// (这里已经在Javabean)中重写了toString 所以会直接打印内容而不是地址值)
System.out.println(s1);//Student{name='张三', age=18, sex='男'[100, 2, 3, 4, 5]}
System.out.println(s2);//Student{name='张三', age=18, sex='男'[100, 2, 3, 4, 5]}
}
深克隆
基本数据类型拷贝过来 字符串复用 引用数据类型会重新创建新的
需要重写方法,或者使用第三方工具
java
protected Object clone() throws CloneNotSupportedException {
//1.先把克隆对象的数组获取出来
int [] data = this.arr;
//2.再创建新的数组,用于存放克隆对象的数组
int [] newdata = new int[data.length];
for (int i = 0; i < data.length; i++) {
newdata[i] = data[i];
}
//3.调用父类中的浅克隆 因为父类中的clone方法是浅克隆 替换克隆出的对象数组地址值
Student student = (Student) super.clone();
//4.将新数组赋值给克隆对象的数组
student.arr = newdata;
return student;
}
五、时间API
5.1 JDK7 旧时间API
5.1.1Date
- 构造方法
-
Date():创建当前系统时间的 Date 对象 -
Date(long time):传入毫秒时间戳,创建对应时间对象(时间戳:1970‑01‑01 00:00:00 GMT 到该时间的毫秒数)2.方法
-
getTime():把时间变成毫秒时间戳
-
before/after:比较两个时间谁早谁晚
java
//创建对象表示当前时间
Date d1 = new Date();
System.out.println(d1);
//创建对象表示一个指定的时间
Date d2 = new Date(0L);
System.out.println(d2);//Thu Jan 01 08:00:00 CST 1970
//settime设置时间
//1000毫秒 = 1秒
d1.setTime(1000l);//Thu Jan 01 08:00:01 CST 1970
System.out.println(d1);
3.小练习
- 打印时间原点一年以后的时间
Java
private static void extracted() {
Date d1 = new Date(0);
System.out.println(d1);//Thu Jan 01 08:00:00 CST 1970
long time = d1.getTime();
time = time + 1000l*60*60*24*365;
d1.setTime(time);
System.out.println(d1);//Fri Jan 01 08:00:00 CST 1971
}
- 定义任意两个date对象,比较哪个时间在前,哪个时间在后
Java
private static void max() {
Random r = new Random();
Date date01 = new Date(Math.abs(r.nextInt()));
Date date02 = new Date(Math.abs(r.nextInt()));
System.out.println(date01);
System.out.println(date02);
long time01 = date01.getTime();
long time02 = date02.getTime();
if (time01 > time02) {
System.out.println("time01 > time02");
}else {
System.out.println("time01 < time02");
}
}
5.1.2 SimpleDateFormat
(配合 Date 做格式化解析)
- 作用
format(Date):Date → 字符串(日期格式化)parse(String):字符串 → Date(日期解析,会抛出ParseException异常)
| 符号 | 含义 |
|---|---|
| yyyy | 4 位年 |
| MM | 2 位月份 |
| dd | 日 |
| HH | 24 小时制小时 |
| mm | 分钟 |
| ss | 秒 |
| E | 星期 |
3.小练习
3.1
Java
public static void main(String[] args) throws IOException, CloneNotSupportedException, ParseException {
//把2020-01-01转换为日期格式并打印
// 可以理解为将一个字符串时间 从它本身的模板中解析出来,解析出来的叫时间对象 再把时间对象套入新的模板中
// 1 先定义字符串表示时间
String str = "2020-01-01";
// 2 定义与字符串相同的日期格式并进行解析
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(str);
// 3 定义新的日期格式并进行转换
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy年MM月dd日");
String dateStr = sdf1.format(date);
System.out.println(dateStr); // 2020年01月01日
3.2
java
/*肯打鸡限时秒杀
1 元秒杀
葡式蛋挞(1 只)兑换券
秒杀开始时间:2023 年 11 月 11 日 0:0:0
秒杀结束时间:2023 年 11 月 11 日 0:10:0
需求
小贾下单并付款的时间为:2023 年 11 月 11 日 0:01:00
小皮下单并付款的时间为:2023 年 11 月 11 日 0:11:0
用代码说明这两位同学有没有参加上秒杀活动?*/
SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 HH:mm:ss");
Date startTime = sdf.parse("2023 年 11 月 11 日 0:0:0");
Date endTime = sdf.parse("2023 年 11 月 11 日 0:10:0");
Date jiaTime = sdf.parse("2023 年 11 月 11 日 0:01:00");
Date piTime = sdf.parse("2023 年 11 月 11 日 0:11:00");
if (jiaTime.after(startTime) && jiaTime.before(endTime)) {
System.out.println("小贾参加了秒杀活动");
} else {
System.out.println("小贾没有参加秒杀活动");
}
if (piTime.after(startTime) && piTime.before(endTime)) {
System.out.println("小皮参加了秒杀活动");
} else {
System.out.println("小皮没有参加秒杀活动");
}
5.1.3 Calendar
1.获取方法 :抽象类,不能 new 对象 ,只能用Calendar.getInstance()拿实例。
Java
// 获取当前系统时间的日历对象
Calendar cal = Calendar.getInstance();
*** 和 Date 互相转换**
// Calendar → Date
Date date = cal.getTime();
// Date → Calendar
cal.setTime(date);
getTime():把日历存的时间,包装成 Date 对象返回(就是你刚才看的代码)setTime(date):把 Date 里面的时间,赋值给 Calendar 日历对象
2.常用方法
get () 获取年月日时分秒(超级大坑)
cal.get(Calendar.YEAR); // 年,正常
cal.get(Calendar.MONTH); // ⚠️重点坑:月份 **0‑11**!0=1月,11=12月!拿出来要+1才是现实月份
cal.get(Calendar.DAY_OF_MONTH);// 月中的几号(1‑31)
cal.get(Calendar.HOUR_OF_DAY);// 24小时制小时
cal.get(Calendar.MINUTE); // 分钟
cal.get(Calendar.SECOND); // 秒
坑:打印月份记得
cal.get(Calendar.MONTH)+1,不然永远少 1 个月。
set () 设置时间
// 直接设置 年,月,日,时,分,秒
cal.set(2023,10,11,0,10,0);
// 注意第二个参数月份!10代表11月!不是10月!
// 单独修改某一个字段
cal.set(Calendar.YEAR,2025);
add () 做时间加减(最常用)
修改日历本身对象,会自动进位,比如 12 月加 1 个月自动变成下一年 1 月
cal.add(Calendar.DAY_OF_MONTH, 3); // 加3天
cal.add(Calendar.DAY_OF_MONTH, -2); // 减2天
cal.add(Calendar.MONTH, 1); // 加1个月
⚠️Calendar 是可变对象,add、set 直接修改原对象,不是返回新对象!和 Java8 新时间类不一样!
add vs roll(了解)
add():会联动进位,12 月 + 1 月 → 下一年 1 月(干活用这个)roll():只改当前字段,不联动年月,几乎不用CSDN博...。
常用常量
| 常量 | 含义 |
|---|---|
| Calendar.YEAR | 年 |
| Calendar.MONTH | 月份 (0‑11) |
| Calendar.DAY_OF_MONTH | 当月几号 |
| Calendar.DAY_OF_YEAR | 一年当中第几天 |
| Calendar.HOUR_OF_DAY | 24 小时制小时 |
细节1.
Calendar是一个抽象类 不能直接new出来 需要用静态方法获取到子类对象
底层原理:会根据系统的不同时区获取不同的日历对象,默认为当前时间
会把时间中的纪元,年,月,日,时,分,秒都放进一个数组中
细节2.
月份:范围0~11 如果获取的是0实际上得到的是一月
星期:在老外眼里星期日就是一周中的第一天 1(星期天) 2(星期一)
java
public static void main(String[] args) {
Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
// Date d = new Date(0l);
// c.setTime(d);
long timeInMillis = c.getTimeInMillis();//拿到时间毫秒值
c.setTimeInMillis(0l);//给日历对象设置时间毫秒值
System.out.println(c.getTime());//Fri Jan 23 14:01:44 CST 2026
c.set(Calendar.HOUR_OF_DAY,0);//修理日历中某的字段的信息
c.add(Calendar.DAY_OF_MONTH,1);//为某个字段的信息增加或减少指定的值
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH)+1;
int day = c.get(Calendar.DAY_OF_MONTH);
int week = c.get(Calendar.DAY_OF_WEEK);
System.out.println(year+" "+month+" "+day+" "+getweek(week));//2026 1 24 星期六
getweek(week);
}
private static String getweek(int week) {
String arr[] = {"","星期天","星期一","星期二","星期三","星期四","星期五","星期六"};
return arr[week];
}
}
3.总结
Calendar 缺点(面试必背)
- 月份从 0 开始,巨容易写错 bug
- 可变对象:set/add 直接改自己,不是返回新对象
- 线程不安全,多线程不能共用同一个 Calendar 实例稀土掘金
- API 难用,Java8 以后推荐用 LocalDateTime,新项目尽量不用 Calendar
5.2 JDK8 java.time 新时间API
5.2.1 时间对象
全部来自 java.time,都是不可变类,没有 new 构造方法,使用静态方法创建对象
1.ZoneId 时区类
作用:专门存时区信息,比如亚洲上海、纽约时区。
创建对象(没有 new,静态方法)
| 方法 | 作用 |
|---|---|
ZoneId.of("Asia/Shanghai") |
通过时区字符串指定时区,上海东八区 |
ZoneId.systemDefault() |
获取本机系统默认时区(我们电脑就是 Asia/ |
java
//1.获取Java中支持的所有时区
Set<String> ZoneIds = ZoneId.getAvailableZoneIds();
System.out.println(ZoneIds);
//2.获取系统默认时区
ZoneId zoneId1 = ZoneId.systemDefault();
System.out.println(zoneId1);
//3.获取一个指定时区
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
System.out.println(zoneId);
白话:只是个时区标签 ,本身没有年月日时分秒。
中国时区写:
Asia/Shanghai,不要写 + 8。
2. Instant 时间戳(UTC 标准时间)
作用:代表世界标准 UTC 时间线上的一个瞬间,存时间戳(1970‑01‑01 00:00:00 UTC 起算)。
1.21创建对象(静态方法,无 new)
| 方法 | 功能 |
|---|---|
Instant.now() |
获取当前 UTC 标准时间 |
Instant.ofEpochMilli(long 毫秒) |
用毫秒时间戳构建 Instant(1970 基准) |
1.22常用方法
| 方法 | 作用 |
|---|---|
long toEpochMilli() |
转成毫秒时间戳 |
ZonedDateTime atZone(ZoneId zoneId) |
给 Instant 套上时区 → 返回 ZonedDateTime |
boolean isBefore(Instant other) |
比较时间,是否在另一个时间之前 |
boolean isAfter(Instant other) |
比较时间,是否在另一个时间之后 |
Instant ins = Instant.now();
// 加时区
ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
// 获取毫秒
long ms = ins.toEpochMilli();
和 Date 互转
-
date.toInstant()Date → Instant -
Date.from(instant)Instant → DateInstant now = Instant.now(); // 获取当前UTC时间戳
-
不带时区!全球同一时刻,Instant 的值完全一样。
-
新旧时间 API 转换的桥梁:Date ↔ 新时间类,都靠 Instant 中转。
-
对应老版
java.util.Date,Date 底层本质就是 Instant。
白话:全世界统一的 "绝对时间点",没有北京时间、纽约时间概念,就是时间轴上的一个点。
java
//1.获取当前的时间Instant对象
Instant instant = Instant.now();
System.out.println(instant);
//2.根据(秒/毫秒/纳秒)获取Instant对象
Instant instant1 = Instant.ofEpochMilli(1000l);//根据毫秒获取对象
System.out.println(instant1);
Instant instant2 = Instant.ofEpochSecond(1l);//根据秒获取对象
System.out.println(instant2);//根据秒和纳秒获取对象
Instant instant3 = Instant.ofEpochSecond(2l, 1000000000l);
System.out.println(instant3);
//3.获取指定时区的时间
ZonedDateTime zonedDateTime = Instant.now().atZone(ZoneId.of("Asia/Shanghai"));
System.out.println(zonedDateTime);
//isBefore 判断是否在前面
Instant instant4 = Instant.ofEpochMilli(100l);
Instant instant5 = Instant.ofEpochSecond(1l);
boolean result = instant4.isBefore(instant5);
System.out.println(result);
//isAfter 判断是否在后面
boolean result1 = instant4.isAfter(instant5);
System.out.println(result);
//4.minusXxx 减少时间系列的方法
Instant instant7 = Instant.ofEpochSecond(3l);//1970-01-01T00:00:03Z
Instant instant8 = instant7.minusSeconds(1);
System.out.println(instant8);//1970-01-01T00:00:02Z
//5.plusXxx 增加时间系列的方法
Instant instant9 = instant8.plusSeconds(1);
System.out.println(instant9);
}
3. ZonedDateTime 带时区的完整时间
= LocalDateTime(年月日时分秒) + ZoneId(时区)
// 当前系统时区的带时区时间
ZonedDateTime zdt = ZonedDateTime.now();
// 指定时区构建
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
白话:完整时间,既有年月日时分秒,又绑定时区。
比如:2026‑08‑19 18:00:00 +08:00[Asia/Shanghai],明确这是北京时间。
常用方法
① 转其他对象
| 方法 | 返回值 | 说明 |
|---|---|---|
LocalDateTime toLocalDateTime() |
LocalDateTime | 丢掉时区,只保留本地年月日时分秒 |
Instant toInstant() |
Instant | 剥离时区,转为 UTC 时间戳 Instant |
LocalDate toLocalDate() |
LocalDate | 只拿年月日 |
LocalTime toLocalTime() |
LocalTime | 只拿时分秒 |
② 时间加减(返回新对象,原对象不变)
| 方法 | 作用 |
|---|---|
plusDays(long days) |
加几天 |
minusMonths(long months) |
减几个月 |
| withXxx (long days) | 修改时间系列的方法 |
③ 时间比较
| 方法 | 作用 |
|---|---|
isBefore(ZonedDateTime other) |
是否早于另一个时间 |
isAfter(ZonedDateTime other) |
是否晚于另一个时间 |
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.systemDefault());
Instant instant = zdt.toInstant();
LocalDateTime ldt = zdt.toLocalDateTime();
LocalDateTime 转 ZonedDateTime
LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
案例
java
public static void main(String[] args) {
//1.获得当前时间的ZoneDateTime对象(带时区)
ZonedDateTime now = ZonedDateTime.now();
System.out.println(now);//2026-01-23T14:36:48.289692100+08:00[Asia/Shanghai]
//2.获得指定时间的ZoneDatetime对象(带时区)
//按年月日时分秒纳秒时区指定
ZonedDateTime.of(2026,6,16,23,23,
22,23, ZoneId.of("Asia/Shanghai"));
//3.通过Instant+时区的方法获取指定事件对象
Instant instant = Instant.ofEpochMilli(0l);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
System.out.println(ZonedDateTime.ofInstant(instant, zoneId));//1970-01-01T08:00+08:00[Asia/Shanghai]
//4.withXxx 修改时间系列的方法
ZonedDateTime zonedDateTime = now.withYear(2000);
System.out.println(zonedDateTime);//2000-01-23T14:48:58.668346200+08:00[Asia/Shanghai]
//减少时间系列的方法
ZonedDateTime zonedDateTime1 = zonedDateTime.minusDays(1);
System.out.println(zonedDateTime1);//2000-01-22T14:54:56.174043700+08:00[Asia/Shanghai]
//增加时间系列的方法
ZonedDateTime zonedDateTime2 = zonedDateTime.plusDays(1);
System.out.println(zonedDateTime2);//2000-01-24T14:54:56.174043700+08:00[Asia/Shanghai]
}
/*jdk8出现的时间对象都是不可改变的
如果我们修改 增加或者减少
调用者是不会发生改变的 只会产生新的时间对象
*/
笔记重点总结
- 这三个类全部不能 new,全部用静态方法创建对象
ZoneId:只存时区,没有时间;systemDefault()拿系统时区Instant:UTC 时间戳,桥梁;atZone(zoneId)套上时区得到 ZonedDateTimeZonedDateTime= 本地时间 + 时区;可以转 Instant、LocalDateTime、LocalDate、LocalTime- LocalDateTime没有时区,不能直接转 Instant,必须先 atZone () 变成 ZonedDateTime
转换速记
java
Instant --atZone(zoneId)--> ZonedDateTime --toLocalDateTime()--> LocalDateTime
LocalDateTime --atZone(zoneId)--> ZonedDateTime --toInstant()--> Instant
4. LocalDate (只有:年‑月‑日,没有时分秒)
1.1创建对象(静态方法)
| 方法 | 说明 |
|---|---|
LocalDate.now() |
获取系统当前的年月日 |
LocalDate.of(int year,int month,int dayOfMonth) |
指定年月日构建对象 |
1.2常用获取方法
| 方法 | 作用 |
|---|---|
int getYear() |
获取年 |
int getMonthValue() |
获取月份(1‑12,没有 0 坑!) |
int getDayOfMonth() |
获取当月几号 |
int getDayOfYear() |
获取一年中的第几天 |
DayOfWeek getDayOfWeek() |
获取星期 |
1.3时间加减(返回新对象)
| 方法 | 作用 |
|---|---|
plusDays(long n) |
加 n 天 |
plusMonths(long n) |
加 n 月 |
minusDays(long n) |
减 n 天 |
minusYears(long n) |
减 n 年 |
1.4比较
| 方法 | 作用 |
|---|---|
isBefore(LocalDate other) |
是否在另一个日期之前 |
isAfter(LocalDate other) |
是否在另一个日期之后 |
isEqual(LocalDate other) |
日期是否相等 |
示例
Java
LocalDate date = LocalDate.of(2023,11,11);
System.out.println(date.getMonthValue()); //11
案例
Java
public static void main(String[] args) {
//当前时间的日历对象 包括年月日
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
//获得指定时间的日历对象
LocalDate localDate1 = LocalDate.of(2024,4,2);
System.out.println(localDate1);
System.out.println("==========================");
//get方法获取日历中每个属性的值
//年
int year = localDate.getYear();
System.out.println(year);//2026
//月: 第一种形式
int month = localDate.getMonthValue();
System.out.println(month);//1
// 第二种形式
Month month1 = localDate.getMonth();
System.out.println(month1.getValue());//1
//日
int day = localDate.getDayOfMonth();
System.out.println(day);//23
//周
DayOfWeek dayOfWeek = localDate1.getDayOfWeek();
System.out.println(dayOfWeek); //TUESDAY
System.out.println(dayOfWeek.getValue());//2
System.out.println("==========================");
//is开头的方法表示判断
boolean after = localDate.isAfter(localDate);
System.out.println(after);//false
boolean after1 = localDate1.isAfter(localDate);
System.out.println(after1);//false
System.out.println("==========================");
//with开头的表示修改方法 只能修改年月日
LocalDate localDate2 = localDate1.withYear(2000);
System.out.println(localDate2);//2000-04-02
System.out.println("==========================");
//minus开头的方法表示减少,只能减少年月日
LocalDate localDate3 = localDate.minusYears(1);
System.out.println(localDate3);//2025-01-23
//plus开头的方法表示增加,只能增加年月日
LocalDate localDate4 = localDate.plusYears(1);
System.out.println(localDate4);//2027-01-23
System.out.println("==========================");
//判断今天是不是你生日
LocalDate bir = LocalDate.of(2026, 1, 12);
Month today = Month.from(LocalDate.now());
System.out.println("今天是你的生日吗"+today.equals(bir));
}
5. LocalTime(只有:时‑分‑秒,没有年月日)
2.1创建对象
| 方法 | 说明 |
|---|---|
LocalTime.now() |
获取当前时分秒 |
LocalTime.of(int hour,int minute,int second) |
指定时分秒构建 |
2.2常用获取
| 方法 | 作用 |
|---|---|
int getHour() |
小时 (24 小时制) |
int getMinute() |
分钟 |
int getSecond() |
秒 |
2.3加减、比较
plusHours()、minusMinutes()、isBefore()、isAfter()
java
LocalTime time = LocalTime.of(0,1,0);
案例
Java
public static void main(String[] args) {
// 获取当前日历对象 包括时分秒
LocalTime now = LocalTime.now();
System.out.println("今天的时间"+now);
int hour = now.getHour();//时
System.out.println(hour);
int minute = now.getMinute();//分
System.out.println(minute);
int second = now.getSecond();//秒
System.out.println(second);
int nano = now.getNano();//纳秒
System.out.println(nano);
System.out.println("==========================");
System.out.println(LocalTime.of(11, 12));
System.out.println(LocalTime.of(11, 12, 30));
System.out.println(LocalTime.of(11, 12, 30,2000));
LocalTime localTime = LocalTime.of(11, 12, 30,2000);
System.out.println("==========================");
//is系列的方法
System.out.println(localTime.isBefore(now));//true
System.out.println(localTime.isAfter(now));//false
//with系列的方法 只能修改时分秒
System.out.println( now.withHour(2));//02:31:08.892886700
//minus系列的方法 只能减少时分秒
System.out.println(now.minusHours(2));//15:31:08.892886700
//plus系列的方法,只能增加时分秒
System.out.println(now.plusHours(2));//19:31:08.892886700
6. LocalDateTime(年月日 + 时分秒,最常用,不带时区)
3.1创建对象
| 方法 | 说明 |
|---|---|
LocalDateTime.now() |
获取当前完整本地时间 |
LocalDateTime.of(int y,int m,int d,int h,int mi,int s) |
指定年月日时分秒创建 |
LocalDateTime.of(LocalDate date,LocalTime time) |
传入 LocalDate+LocalTime 组合生成 |
3.2获取组件
| 方法 | 返回值 | 作用 |
|---|---|---|
toLocalDate() |
LocalDate | 提取年月日部分 |
toLocalTime() |
LocalTime | 提取时分秒部分 |
getYear() |
int | 年 |
getMonthValue() |
int | 月 (1‑12) |
getDayOfMonth() |
int | 日 |
getHour() |
int | 小时 |
getMinute() |
int | 分钟 |
3.3时间加减(返回新对象,原对象不变)
Java
plusDays() plusMonths() plusHours()
minusDays() minusMonths() minusHours()
3.4比较
isBefore()、isAfter()
⚠️重要:加上时区转为 ZonedDateTime
LocalDateTime 本身没有时区,不能直接转 Instant
Java
// LocalDateTime + 时区 → ZonedDateTime
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
格式化解析(搭配 DateTimeFormatter)
java
//格式化:对象→字符串
String str = ldt.format(DateTimeFormatter.ofPattern("yyyy‑MM‑dd HH:mm:ss"));
//解析:字符串→对象
LocalDateTime ldt2 = LocalDateTime.parse(str,DateTimeFormatter.ofPattern("yyyy‑MM‑dd HH:mm:ss"));
案例
Java
public static void main(String[] args) {
//当前时间的日历对象 包括年月日时分秒
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("今天是"+localDateTime);//今天是2026-01-23T16:17:35.229178800
System.out.println(localDateTime.getYear());//年 2026
System.out.println(localDateTime.getMonthValue());//月 1
System.out.println(localDateTime.getDayOfMonth());//日23
System.out.println(localDateTime.getHour());//时 16
System.out.println("==========================");
//日:当年的第几天
System.out.println(localDateTime.getDayOfYear());
//月:
Month month = localDateTime.getMonth();
System.out.println(month.getValue());//1
//星期:
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
System.out.println(dayOfWeek.getValue());//5
System.out.println("==========================");
//转换为LocalData对象
LocalDate ld = localDateTime.toLocalDate();
System.out.println(ld);//2026-01-23
//转换为LocalTime对象
LocalTime lt = localDateTime.toLocalTime();
System.out.println(lt);//16:36:03.871771300
System.out.println(lt.getHour());//16
System.out.println(lt.getMinute());//36
System.out.println(lt.getSecond()); //3
5.2.2 格式化类 DateTimeFormatter
DateTimeFormatter
包:
java.time.format.DateTimeFormatter,Java8 新版格式化工具,线程安全!替代 SimpleDateFormat不可变类,不能 new,通过静态方法创建实例
1.创建对象(静态方法)
| 方法 | 说明 |
|---|---|
DateTimeFormatter.ofPattern("yyyy‑MM‑dd HH:mm:ss") |
自定义格式模板,最常用 |
模式符号和老的SimpleDateFormat一样
yyyy4 位年MM月份 (01‑12)dd日期HH24 小时小时mm分钟ss秒
2.两大核心功能
1. 格式化:时间对象 → 字符串 format ()
LocalDate / LocalTime / LocalDateTime / ZonedDateTime 都有
.format(格式化器)方法
java
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy‑MM‑dd HH:mm:ss");
String timeStr = ldt.format(fmt);
2. 解析:字符串 → 时间对象 parse ()
时间类的静态 parse 方法,传入字符串 + formatter
java
String s = "2023‑11‑11 00:01:00";
LocalDateTime ldt = LocalDateTime.parse(s, fmt);
和旧 SimpleDateFormat 对比
| SimpleDateFormat | DateTimeFormatter | |
|---|---|---|
| 所属包 | java.text | java.time.format |
| 线程安全 | ❌不安全,不能共享 | ✅线程安全,可以全局共用 |
| 创建方式 | new 对象 | 静态ofPattern() |
| 格式化 | sdf.format(date) | ldt.format(formatter) |
| 解析 | sdf.parse(str) | LocalDateTime.parse(str,formatter) |
⚠️注意点
-
没有抛出受检异常 ParseException!
SimpleDateFormat#parse需要throws ParseException;新版
parse如果格式错误,抛出DateTimeParseException(运行时异常,不用写 throws 声明)。 -
不能直接格式化 Date 对象
DateTimeFormatter 是给 java.time 新时间类用的。
如果是老 Date:先转成 Instant→ZonedDateTime,再格式化。
java
Date date = new Date();
ZonedDateTime zdt = date.toInstant().atZone(ZoneId.systemDefault());
String str = zdt.format(fmt);
完整示例代码
java
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class TestFormat {
public static void main(String[] args) {
//1.创建格式化器
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy‑MM‑dd HH:mm:ss");
//格式化:对象→字符串
LocalDateTime now = LocalDateTime.now();
String s1 = now.format(fmt);
System.out.println(s1);
//解析:字符串→LocalDateTime对象
String timeText = "2023‑11‑11 00:10:00";
LocalDateTime parseTime = LocalDateTime.parse(timeText, fmt);
System.out.println(parseTime);
}
}
笔记总结
DateTimeFormatter.ofPattern("格式")创建实例- 对象.format (formatter):时间对象转字符串
LocalDateTime.parse(字符串,formatter):字符串解析成时间对象- 线程安全,项目优先用,不要用 SimpleDateFormat
- 只服务 java.time 新类;老 Date 要先转换成 ZonedDateTime 再使用。
5.2.3 时间间隔工具类
包:
java.time,用来计算时间间隔、时间差,配合 java.time 新时间类使用
1. Duration (时分秒:时间间隔,处理秒、毫秒)
适合:LocalTime、LocalDateTime、Instant;处理时分秒级别的时间差
不处理年月日!
1.1创建对象
| 方法 | 作用 |
|---|---|
Duration.between(开始,结束) |
计算两个时间之间的间隔 |
Duration.ofHours(2) |
直接构建 2 小时间隔 |
Duration.ofMinutes(30) |
构建 30 分钟间隔 |
1.2常用方法
| 方法 | 作用 |
|---|---|
long toHours() |
把间隔转成总小时数 |
long toMinutes() |
转总分钟 |
long toSeconds() |
转总秒 |
long toMillis() |
转总毫秒 |
plusHours(1) |
间隔加 1 小时 |
minusMinutes(5) |
间隔减 5 分钟 |
示例:
java
LocalDateTime t1 = LocalDateTime.of(2023,11,11,0,1,0);
LocalDateTime t2 = LocalDateTime.of(2023,11,11,0,10,0);
Duration duration = Duration.between(t1,t2);
System.out.println(duration.toMinutes()); //9分钟
⚠️ 如果传入 LocalDate(只有年月日)会报错!Duration 只认带时分秒的对象。
案例
java
public static void main(String[] args) {
LocalDate now = LocalDate.now();
System.out.println(now);//2026-01-24
LocalDate birthday = LocalDate.of(2001,1,1);
System.out.println(birthday);//2001-01-01
Period period = Period.between(birthday,now);
System.out.println("相差的时间间隔Period is " + period);//相差的时间间隔Period is P25Y23D
System.out.println(period.getYears());//25
System.out.println(period.getMonths());//0
System.out.println(period.getDays());//23
System.out.println(period.toTotalMonths());//300
2. Period(年月日间隔,只处理年、月、日)
专门给 LocalDate 使用,只算年、月、日,忽略时分秒
2.1创建对象
| 方法 | 作用 |
|---|---|
Period.between(LocalDate start,LocalDate end) |
计算两个日期相差几年几月几日 |
Period.ofYears(1) |
构建 1 年间隔 |
Period.ofMonths(2) |
构建 2 个月间隔 |
Period.ofDays(10) |
构建 10 天间隔 |
2.2常用方法
| 方法 | 作用 |
|---|---|
int getYears() |
获取间隔几年 |
int getMonths() |
获取间隔几个月 |
int getDays() |
获取间隔几天 |
示例
java
LocalDate d1 = LocalDate.of(2023,1,1);
LocalDate d2 = LocalDate.of(2025,3,5);
Period period = Period.between(d1,d2);
System.out.println(period.getYears()); //2
System.out.println(period.getMonths()); //2
System.out.println(period.getDays()); //4
⚠️只接收 LocalDate!传入 LocalDateTime 会自动剥离时分秒。
案例
java
//用于计算两个时间间隔(秒,纳秒)
LocalTime time = LocalTime.now();
System.out.println(time);
LocalTime time1 = LocalTime.of(1,1,1);
System.out.println(time1);
Duration duration = Duration.between(time,time1);
System.out.println(duration);
System.out.println(duration.toDays());
System.out.println(duration.toHours());
System.out.println(duration.toMinutes());
3. ChronoUnit (工具枚举,最灵活,工作最常用)
枚举类,可以直接计算两个时间相差【指定单位】,天、小时、分钟、月、年都可以。
3.1常用常量
java
ChronoUnit.YEARS //年
ChronoUnit.MONTHS //月
ChronoUnit.DAYS //天
ChronoUnit.HOURS //小时
ChronoUnit.MINUTES //分钟
ChronoUnit.SECONDS //秒
3.2核心方法 between(a,b)
java
LocalDateTime l1 = LocalDateTime.of(2023,11,11,0,1,0);
LocalDateTime l2 = LocalDateTime.of(2023,11,11,2,5,0);
long day = ChronoUnit.DAYS.between(l1,l2);
long hour = ChronoUnit.HOURS.between(l1,l2);
long minute = ChronoUnit.MINUTES.between(l1,l2);
System.out.println(day); //0
System.out.println(hour); //2
System.out.println(minute); //124
3.3还可以给时间对象做加减:
java
LocalDateTime ldt = LocalDateTime.now();
ldt.plus(3, ChronoUnit.DAYS); //加3天
ldt.minus(2, ChronoUnit.MONTHS); //减2个月
✅三者对比笔记(必背)
| 类 | 适用对象 | 处理粒度 | 特点 |
|---|---|---|---|
| Duration | LocalTime / LocalDateTime / Instant | 时、分、秒、毫秒 | 不能处理年月日 |
| Period | LocalDate | 年、月、日 | 不能处理时分秒 |
| ChronoUnit | LocalDate / LocalDateTime /ZonedDateTime/Instant | 年 / 月 / 日 / 时 / 分 / 秒 | 万能,直接得到总数量,开发首选 |
重点区别举例
- 2023‑01‑01 ~ 2023‑03‑05
- Period:
P2M4D→ 2 个月零 4 天 - ChronoUnit.DAYS.between:直接返回总天数 63
- Period:
Period 是拆分成几年几月几日;ChronoUnit 直接返回换算后的总数值。
坑点
- Duration 不要传 LocalDate,会抛异常。
- Period 只看年月日,时分秒直接丢弃。
between(开始,结束),结束在开始前面,返回负数。
java
//结束时间 < 开始时间,得到负数
Duration.between(t2,t1).toMinutes(); // -9
案例'
Java
LocalDateTime time = LocalDateTime.now();
System.out.println(time);
LocalDateTime bir = LocalDateTime.of(2001, 6, 17, 6, 20, 20);
System.out.println(bir);
System.out.println("相差的年数为"+ChronoUnit.YEARS.between(bir,time));
System.out.println("相差的月数为"+ChronoUnit.MONTHS.between(bir,time));
System.out.println("相差的天数为"+ChronoUnit.DAYS.between(bir,time));
System.out.println("相差的小时数为"+ChronoUnit.HOURS.between(bir,time));
System.out.println("相差的分钟数为"+ChronoUnit.MINUTES.between(bir,time));
System.out.println("相差的秒数为"+ChronoUnit.SECONDS.between(bir,time));
System.out.println("相差的毫秒数为"+ChronoUnit.MILLIS.between(bir,time));
System.out.println("相差的纳秒数为"+ChronoUnit.NANOS.between(bir,time));
System.out.println("相差的半天数为"+ChronoUnit.HALF_DAYS.between(bir,time));
System.out.println("相差的十年数为"+ChronoUnit.DECADES.between(bir,time));
System.out.println("相差的周数为"+ChronoUnit.WEEKS.between(bir,time));
System.out.println("相差的世纪(百年)数为"+ChronoUnit.CENTURIES.between(bir,time));
System.out.println("相差的千年数为"+ChronoUnit.MILLENNIA.between(bir,time));
System.out.println("相差的纪元数为"+ChronoUnit.ERAS.between(bir,time));
一句话记忆
- Duration:算时分秒时间间隔
- Period:算年月日间隔(拆成年、月、日三部分)
- ChronoUnit:万能工具,直接拿相差总多少年 / 总多少天 / 总小时,实际开发用最多
- LocalDate、LocalTime、LocalDateTime
- Instant、ZoneId、ZonedDateTime
- DateTimeFormatter
- Duration、Period、ChronoUnit