日期与数组工具类

day04 【日期与数组工具类】

第一章 包装类

Java中的8种基本数据类型还不是对象,所以要把它们变成对象,变成对象之后,可以提供一些方法对数据进行操作。

//把基本类型的数据包装成对象

1.1 概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
包装类的概念
ArrayList集合存储基本类型数据时,要求<>中必须指定基本类型对应的引用类型(包装类)

基本类型 引用类型(包装类)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

集合中永远只能存储引用类型:
只需要在创建集合对象时,<>中指定对应的包装类,其它操作都可以按照基本类型完成

引用类型(包装类)并不是对基本类型的简单替换,而是包装类中提供了大量的方法完成相关功能
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class BaoZhuang {
public static void main(String[] args) {
//创建ArrayList集合对象,存储整数
//ArrayList<int> list = new ArrayList<int>();//错误:<>中不能写基本类型
ArrayList<Integer> list = new ArrayList<>();

list.add(100);
list.add(200);
list.add(300);
list.add(500);

//遍历
for (int i = 0; i < list.size(); i++) {
int num = list.get(i);
System.out.println(num);
}
}
}

1.2 Integer类对象的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
java.lang.Integer类对象的创建
Integer 类在对象中包装了一个基本类型 int 的值。
构造方法:
public Integer(int value):
把构造方法int参数value,转换成Integer对象

public Integer(String value):
把构造方法String参数value,转换成Integer对象
思考:
Integer类中有没有返回值是Integer类型的方法?

静态方法:
public static Integer valueOf(int i):
作用: 把方法参数int类型的i转换成Integer类型并返回

public static Integer valueOf(String i):
作用: 把方法参数String类型的i转换成Integer类型并返回

注意:
1.构造方法/静态方法参数不可以超出int的范围
2.构造方法/静态方法如果采用String的参数,参数中不可以包含非数字字符
*/

核心补充:Integer 的「缓存机制」(面试常考)

这是 new Integer()Integer.valueOf() 最关键的区别:

  • new Integer(int value):每次都会创建一个新的对象,即使值相同。
  • Integer.valueOf(int i):会先检查值是否在 -128 到 127 之间(默认缓存范围),如果在,直接返回缓存池中的已有对象;如果不在,才创建新对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 用构造方法创建
Integer a = new Integer(100);
Integer b = new Integer(100);
System.out.println(a == b); // false(两个不同的对象)

// 用 valueOf 创建
Integer c = Integer.valueOf(100);
Integer d = Integer.valueOf(100);
System.out.println(c == d); // true(缓存池中的同一个对象)

// 超出缓存范围
Integer e = Integer.valueOf(200);
Integer f = Integer.valueOf(200);
System.out.println(e == f); // false(超出范围,创建新对象)

1.3 Integer类的常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
java.lang.Integer类: 内部会包装一个int/String数字
1.思考:
如何获取int数据的取值范围? 最大值和最小值(通过Integer类中的常量)
public static final int MAX_VALUE = 0x7f ff ff ff;
public static final int MIN_VALUE = 0x80000000;

2.思考:
如何获取int数字对应的二进制/八进制/十六进制数字?
public static String toBinaryString(int i):
把方法参数int类型的i转换成二进制,并返回对应的String结果

public static String toOctalString(int i):
把方法参数int类型的i转换成八进制,并返回对应的String结果

public static String toHexString(int i):
把方法参数int类型的i转换成十六进制,并返回对应的String结果

0b: 表示二进制
0x: 表示十六进制
0: 表示八进制
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Demo04IntegerMethod {
public static void main(String[] args) {
//int最大值
System.out.println(Integer.MAX_VALUE);
//int最小值
System.out.println(Integer.MIN_VALUE);

//定义int变量num
int num = 100;
//转换成二进制
System.out.println(Integer.toBinaryString(num));//1100100
//转换成八进制
System.out.println(Integer.toOctalString(num));//144
//转换成十六进制
System.out.println(Integer.toHexString(num));//64
}
}

1.4 包装类的自动装箱拆箱

1
2
3
4
5
6
7
8
/*
包装类的自动装箱拆箱
自动装箱:
基本类型数据,可以自动转换为对应的引用类型(包装类),
自动拆箱:
引用类型数据(包装类),可以自动转换为对应的基本类型
都是是自动完成
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test02_1 {
public static void main(String[] args) {
// 1: 手动装箱
Integer i1 = new Integer(123); // JDK9已经标记为过期了,不推荐使用了
System.out.println(i1);

Integer i2 = Integer.valueOf(345);
System.out.println(i2);
// 2: 自动装箱
Integer i3 = 456;
System.out.println(i3);

// 手动拆箱
int i4 = i1.intValue();
// 自动拆箱
int i5 = i2;
System.out.println(i4);
System.out.println(i5);
}
}

1.5 基本类型转换成对应的字符串

在开发中,经常使用包装类对字符串和基本类型数据进行相互转换。

  • 把字符串转换为数值型数据:包装类.parseXxx(字符串)
1
2
public static int parseInt(String s)
把字符串转换为基本数据类型
  • 将数值型数据转换为字符串:包装类.valueOf(数据);
1
2
public static String valueOf(int a)
把基本类型数据转换为字符串
1
2
3
4
5
6
7
8
9
10
11
/*
基本类型int 转换成 String
1.最简单/最常用的方式:
基本类型int数据 + "" 借助+进行字符串拼接

2.思考: String类中有没有参数是int类型,返回值是String类型方法?
public static String valueOf(int i): 把方法参数int数据i,转换成String类型并返回

3.思考: Integer类中有没有参数是int类型,返回值是String类型方法?
public static String toString(int i)
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Demo06ToString {
public static void main(String[] args) {
int num = 20;
String strNum = num + "";
System.out.println(strNum);//20
System.out.println(strNum+20);//2020

String s = String.valueOf(num);
System.out.println(s);//20
System.out.println(s+20);//2020

String s2 = Integer.toString(num);
System.out.println(s2);//20
System.out.println(s2+20);//2020
}
}

1.6 String解析成对应的基本类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
String解析成对应的基本类型(很常用的)
包装类中除了Character以外,每个包装类都会提供一个静态方法
public static xxx parseXxx(String str):
把方法参数String数据str转换成xxx类型的数据

Integer类:
public static int parseInt(String str):
把方法参数String数据str转换成int类型的数据

Double类:
public static double parseDouble(String str):
把方法参数String数据str转换成double类型的数据

Boolean类:
public static boolean parseBoolean(String str):
把方法参数String数据str转换成boolean类型的数据
*/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Demo07ParseString {
public static void main(String[] args) {
String str = "20";

//把String数据转换成int数据
int num = Integer.parseInt(str);
System.out.println(num);//20
System.out.println(num + 20);//40

String str2 = "66.66";
//把String数据转换成double数据
double num2 = Double.parseDouble(str2);
System.out.println(num2);//66.66
System.out.println(num2 + 33.33);//99.99

String str3 = "true";
boolean reslut = Boolean.parseBoolean(str3);
System.out.println(reslut);//true
System.out.println(!reslut);//false
}
}

1.7案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
练习字符串和基本数据类型的相互转换
*/
public class Test02_2 {
public static void main(String[] args) {
// 1: 把基本数据类型转字符串
String s1 = String.valueOf(123);
System.out.println(s1 instanceof String);

// 2: 把字符串转基本数据类型
int i = Integer.parseInt(s1);
System.out.println(++i);

// 3: 获取包装类的最值
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
}
}

/*
练习字符串和基本数据类型的相互转换的案例
需求:
对字符串中所有的数字,进行升序排序
"22,1,555,128,44,77,99,25,6,888,111"
思路:
1: 对字符串使用 , 切分得到一个字符串数组
2: 转成 int 数组
3: 利用工具排序
4: 将排序后的结果重新转成字符串

*/
public class Test {
public static void main(String[] args) {
String s = "22,1,555,128,44,77,99,25,6,888,111";
// 1: 对字符串使用 , 切分得到一个字符串数组
String[] arr = s.split(",");
// 2: 转成 int 数组
int[] arr2 = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
arr2[i] = Integer.parseInt( arr[i]);
}
// 3: 利用工具排序
Arrays.sort(arr2);
// 4: 将排序后的结果重新转成字符串
String string = Arrays.toString(arr2);
System.out.println(string);
}
}

Date类

Date类,Java中是由这个类的对象用来表示日期或者时间。

Date对象记录的时间是用毫秒值来表示的。

Java语言规定,1970年1月1日0时0分0秒认为是时间的起点,此时记作0,那么1000(1秒=1000毫秒)就表示1970年1月1日0时0分1秒,依次内推。
null

下面是Date类的构造方法,和常见的成员方法

null

  • 创建Date对象:

使用new Date(),这将创建一个代表当前时间的Date对象
使用new Date(long millis),通过传递一个毫秒值来创建一个特定的Date对象。

  • 获取时间毫秒值:

调用Date对象的getTime()方法,它将返回Date对象表示的毫秒值。
使用System.currentTimeMillis(),直接获取当前时间的毫秒值,而无需创建Date对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Test1Date {
public static void main(String[] args) {
// 1、创建一个Date的对象:代表系统当前时间信息的。
Date d = new Date();
System.out.println(d);

// 2、拿到时间毫秒值。
long time = d.getTime();
System.out.println(time);

// 3、把时间毫秒值转换成日期对象: 2s之后的时间是多少。
time += 2 * 1000;
Date d2 = new Date(time);
System.out.println(d2);

// 4、直接把日期对象的时间通过setTime方法进行修改
Date d3 = new Date();
d3.setTime(time);
System.out.println(d3);
}
}
  • 我们把Date对象转换为指定格式的日期字符串这个操作,叫做日期格式化
  • 反过来把指定格式的日期符串转换为Date对象的操作,叫做日期解析

SimpleDateFormat类

接下来,我们先演示一下日期格式化,需要用到如下的几个方法

null

注意:创建SimpleDateFormat对象时,在构造方法的参数位置传递日期格式,而日期格式是由一些特定的字母拼接而来的。

1
2
3
4
5
6
7
8
9
10
11
12
字母	   表示含义
yyyy 年
MM 月
dd 日
HH 时
mm 分
ss 秒
SSS 毫秒

"2022年12月12日" 的格式是 "yyyy年MM月dd日"
"2022-12-12 12:12:12" 的格式是 "yyyy-MM-dd HH:mm:ss"
按照上面的格式可以任意拼接,但是字母不能写错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test2SimpleDateFormat {
public static void main(String[] args) throws ParseException {
// 1、准备一些时间
Date d = new Date();
System.out.println(d);

long time = d.getTime();
System.out.println(time);

// 2、格式化日期对象,和时间 毫秒值。
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a");

String rs = sdf.format(d);
String rs2 = sdf.format(time);
System.out.println(rs);
System.out.println(rs2);

// 目标:掌握SimpleDateFormat解析字符串时间 成为日期对象。
String dateStr = "2022-12-12 12:12:11";
// 1、创建简单日期格式化对象 , 指定的时间格式必须与被解析的时间格式一模一样,否则程序会出bug.
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d2 = sdf2.parse(dateStr);
System.out.println(d2);
}
}

日期格式化&解析案例
null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Test3 {
public static void main(String[] args) throws ParseException {
// 目标:完成秒杀案例。
// 1: 创建格式化和解析的工具类对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-M-d H:m:s");
// 2: 准备开始和结束时间的字符串,并解析成日期,然后换算成对应的毫秒值
long start = sdf.parse("2026-3-1 0:0:0").getTime();
long end = sdf.parse("2026-3-1 0:10:0").getTime();
long jia = sdf.parse("2026-3-1 0:3:47").getTime();
long pi = sdf.parse("2026-3-1 0:10:3").getTime();

if(jia >= start && jia <= end){
System.out.println("小贾同学参与成功!");
}else {
System.out.println("小贾同学参与失败!");
}

if(pi >= start && pi <= end){
System.out.println("小皮同学参与成功!");
}else {
System.out.println("小皮同学参与失败!");
}

long now = sdf.parse("2026-3-24 14:49:0").getTime();
long birth = sdf.parse("2003-3-4 0:0:0").getTime();

// 计算天数
long diffMillis = now - birth;
long days = diffMillis / (24 * 60 * 60 * 1000);

System.out.println("出生天数:" + days + "天");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
练习日期的格式化和解析
*/
public class MySimpleDate {
public static void main(String[] args) {
// 1: 创建格式化和解析的工具类对象
SimpleDateFormat sdf = new SimpleDateFormat(); //用无参构造方法,会使用系统的默认格式
Date date = new Date();
String format = sdf.format(date);
System.out.println(format);

// 自己指定格式
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss E");
String format1 = sdf2.format(date);
System.out.println(format1);

// 解析
String s = "2026年03月24日 14:17:49 周五"; //定义一个字符串,注意它的格式必须和 sdf2 的格式完全一致
Date parse = null; //先声明一个 Date 对象 parse,初始值为 null,用来存解析后的结果
try {
parse = sdf2.parse(s);
} catch (ParseException e) {
e.printStackTrace();
System.out.println("字符串的格式与工具中的模式字母不对应,请检查格式!");
}
System.out.println(parse);
//打印解析后的 Date 对象,输出类似 Thu Mar 26 15:40:00 CST 2026 的结果
}
}

Calendar类

Calendar类表示日历,它提供了一些比Date类更好用的方法。

因为Calendar类提供了方法可以直接对日历中的年、月、日、时、分、秒等进行运算。

null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Test4Calendar {
public static void main(String[] args) {

// 1、得到系统此刻时间对应的日历对象。
Calendar now = Calendar.getInstance();
System.out.println(now);

// 2、获取日历中的某个信息
int year = now.get(Calendar.YEAR);
System.out.println(year);

int days = now.get(Calendar.DAY_OF_YEAR);
System.out.println(days);

// 3、拿到日历中记录的日期对象。
Date d = now.getTime();
System.out.println(d);

// 4、拿到时间毫秒值
long time = now.getTimeInMillis();
System.out.println(time);

// 5、修改日历中的某个信息
now.set(Calendar.MONTH, 9); // 修改月份成为10月份。
now.set(Calendar.DAY_OF_YEAR, 125); // 修改成一年中的第125天。
System.out.println(now);

// 6、为某个信息增加或者减少多少
now.add(Calendar.DAY_OF_YEAR, 100);
now.add(Calendar.DAY_OF_YEAR, -10);
now.add(Calendar.DAY_OF_MONTH, 6);
now.add(Calendar.HOUR, 12);
now.set(2026, 11, 22);
System.out.println(now);
}
}

为什么JDK8要新增日期类

1
2
3
4
5
6
7
8
在JDK7的日期类中方法较少,
线程不安全,
对象可变,
精度只能到毫秒;
而JDK8针对以上问题做了补充和优化;
// 1秒 = 1000毫秒
// 1毫秒 = 1000微妙
// 1微妙 = 1000纳秒

LocalDataTime

null

全部都是静态

比如表示年月日用LocalDate类、

表示时间秒用LocalTime类、

表示年月日时分秒用LocalDateTime类等;
null

  • LocalDate类的基本使用
    null
1
同理
  • LocalTime类的基本使用
    null
1
同理
  • LocalDateTime类的基本使用
    null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class Test3_LocalDateTime {
public static void main(String[] args) {
// 0、获取本地日期和时间对象。
LocalDateTime ldt = LocalDateTime.now(); // 年 月 日 时 分 秒 纳秒
System.out.println(ldt);

// 1、可以获取日期和时间的全部信息
int year = ldt.getYear(); // 年
int month = ldt.getMonthValue(); // 月
int day = ldt.getDayOfMonth(); // 日
int dayOfYear = ldt.getDayOfYear(); // 一年中的第几天
int dayOfWeek = ldt.getDayOfWeek().getValue(); // 获取是周几
int hour = ldt.getHour(); //时
int minute = ldt.getMinute(); //分
int second = ldt.getSecond(); //秒
int nano = ldt.getNano(); //纳秒

// 2、修改时间信息:
// withYear withMonth withDayOfMonth withDayOfYear withHour
// withMinute withSecond withNano
LocalDateTime ldt2 = ldt.withYear(2029);
LocalDateTime ldt3 = ldt.withMinute(59);

// 3、加多少:
// plusYears plusMonths plusDays plusWeeks plusHours plusMinutes plusSeconds plusNanos
LocalDateTime ldt4 = ldt.plusYears(2);
LocalDateTime ldt5 = ldt.plusMinutes(3);

// 4、减多少:
// minusDays minusYears minusMonths minusWeeks minusHours minusMinutes minusSeconds minusNanos
LocalDateTime ldt6 = ldt.minusYears(2);
LocalDateTime ldt7 = ldt.minusMinutes(3);

// 5、获取指定日期和时间的LocalDateTime对象:
// public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour,
// int minute, int second, int nanoOfSecond)
LocalDateTime ldt8 = LocalDateTime.of(2029, 12, 12, 12, 12, 12, 1222);
LocalDateTime ldt9 = LocalDateTime.of(2029, 12, 12, 12, 12, 12, 1222);

// 6、 判断2个日期、时间对象,是否相等,在前还是在后: equals、isBefore、isAfter
System.out.println(ldt9.equals(ldt8));
System.out.println(ldt9.isAfter(ldt));
System.out.println(ldt9.isBefore(ldt));

// 7、可以把LocalDateTime转换成LocalDate和LocalTime
// public LocalDate toLocalDate()
// public LocalTime toLocalTime()
// public static LocalDateTime of(LocalDate date, LocalTime time)
LocalDate ld = ldt.toLocalDate();
LocalTime lt = ldt.toLocalTime();
LocalDateTime ldt10 = LocalDateTime.of(ld, lt);
}
}

时区

由于世界各个国家与地区的经度不同,各地区的时间也有所不同,因此会划分为不同的时区。每一个时区的时间也不太一样。

null

null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test4_ZoneId_ZonedDateTime {
public static void main(String[] args) {
// 1、ZoneId的常见方法:
// public static ZoneId systemDefault(): 获取系统默认的时区
ZoneId zoneId = ZoneId.systemDefault();
System.out.println(zoneId.getId());
System.out.println(zoneId);

// public static Set<String> getAvailableZoneIds(): 获取Java支持的全部时区Id
System.out.println(ZoneId.getAvailableZoneIds());

// public static ZoneId of(String zoneId) : 把某个时区id封装成ZoneId对象。
ZoneId zoneId1 = ZoneId.of("America/New_York");

// 2、ZonedDateTime:带时区的时间。
// public static ZonedDateTime now(ZoneId zone): 获取某个时区的ZonedDateTime对象。
ZonedDateTime now = ZonedDateTime.now(zoneId1);
System.out.println(now);

// 世界标准时间
ZonedDateTime now1 = ZonedDateTime.now(Clock.systemUTC());
System.out.println(now1);

// public static ZonedDateTime now():获取系统默认时区的ZonedDateTime对象
ZonedDateTime now2 = ZonedDateTime.now();
System.out.println(now2);

// Calendar instance = Calendar.getInstance(TimeZone.getTimeZone(zoneId1));
}
}

Instant类

通过获取Instant的对象可以拿到此刻的时间,

该时间由两部分组成:从1970-01-01 00:00:00 开始走到此刻的总秒数+不够1秒的纳秒数。
null

该类提供的方法如下图所示,可以用来获取当前时间,也可以对时间进行加、减、获取等操作。

null

作用:可以用来记录代码的执行时间,或用于记录用户操作某个事件的时间点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test5_Instant {
public static void main(String[] args) {
// 1、创建Instant的对象,获取此刻时间信息
Instant now = Instant.now(); // 不可变对象

// 2、获取总秒数
long second = now.getEpochSecond();
System.out.println(second);

// 3、不够1秒的纳秒数
int nano = now.getNano();
System.out.println(nano);
System.out.println(now);
Instant instant = now.plusNanos(111);

// Instant对象的作用:做代码的性能分析,或者记录用户的操作时间点
Instant now1 = Instant.now();
// 代码执行。。。。
Instant now2 = Instant.now();
LocalDateTime l = LocalDateTime.now();
}
}

格式化器

null

null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
使用 JDK8提供的日期格式化的工具类,对 jdk8相关的日期对象进行格式化 和解析
*/
public class MyDTF {
public static void main(String[] args) {
// 1: 获取工具对象
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 2: 获取日期对象
LocalDateTime now = LocalDateTime.now();
// 3: 采用传统的方式,面向工具,调用方法,完成格式化和解析
String format = formatter.format(now);
System.out.println(format);

// 4: 准备一个字符串日期,并解析
String s = "2026-03-24 15:53:04";
//TemporalAccessor parse = formatter.parse(s);
//System.out.println(parse);

// 5: 把工具当成配角(作为参数使用),
// 如果手里已经有日期对象了,则可以面向日期对象,
//调用format方法,传递工具对象,得到结果(格式化用)
System.out.println(now.format(formatter));
// 如果手里没有日期对象了,则可以面向日期类,调用静态方法parse,传递字符串和工具对象,得到结果(解析用)
LocalDateTime parse1 = LocalDateTime.parse(s, formatter);
System.out.println(parse1);
}
}

Period类

其中Period用来计算日期间隔(年、月、日)

Duration用来计算时间间隔(时、分、秒、纳秒)
null

可以用来计算两个日期之间相隔的年、相隔的月、相隔的日。

只能两个计算LocalDate对象之间的间隔

null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
练习 粗粒度的时间间隔对象
*/
public class MyPeriod {
public static void main(String[] args) {
// 1: 准备开始时间和结束时间
LocalDate t1 = LocalDate.of(2001,5,3);
LocalDate t2 = LocalDate.now();
// 2: 获取一个t1和t2的间隔对象
Period between = Period.between(t1, t2);
// 3: 面向间隔对象,获取相关信息
int years = between.getYears();
int months = between.getMonths();
int days = between.getDays();
System.out.println("从"+t1+"到今天,一共经历了:"+years+"年零"+months+"月零"+days+"天");
}
}

Duration类

它是用来表示两个时间对象的时间间隔。

可以用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数;

支持LocalTime、LocalDateTime、Instant等时间

null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
练习 细粒度的时间间隔对象
*/
public class MyDuration {
public static void main(String[] args) {
// 1: 设置登录游戏的时间点对象
LocalDateTime t1 = LocalDateTime.of(2026, 3, 23, 20, 20, 10);
LocalDateTime t2 = LocalDateTime.now();
// 2: 获取时间间隔对象
Duration between = Duration.between(t1, t2);
// 3: 面向间隔对象,获取相关信息
long seconds = between.getSeconds();
System.out.println("从"+t1+"开始到现在,已经连续玩了:"+seconds+"秒的游戏了...");
System.out.println("从"+t1+"开始到现在,已经连续玩了:"+seconds/3600+"小时,零"+seconds%3600/60+"分,零"+seconds%60+"秒的游戏了...");

long hours = between.toHours();
long days = between.toDays();
System.out.println(hours);
System.out.println(days);
}
}

Period有啥作用?

  • 可以用于计算两个LocalDate对象相差的年数、月数、天数。

Duration有啥作用?

  • 可以用于计算两个时间对象相差的天数、小时数、分数、秒数、纳秒数,支持
    LocalTime.LocalDateTime.lnstant等时间。

对象的深克隆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class Phone implements Cloneable{
private String brand;
private double price;
private double[] memory;


@Override
public String toString() {
return "Phone{" +
"brand='" + brand + '\'' +
", price=" + price +
", memory=" + Arrays.toString(memory) +
'}';
}

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

public double getPrice() {
return price;
}

public void setPrice(double price) {
this.price = price;
}

public double[] getMemory() {
return memory;
}

public void setMemory(double[] memory) {
this.memory = memory;
}

public Phone() {
}

public Phone(String brand, double price, double[] memory) {
this.brand = brand;
this.price = price;
this.memory = memory;
}

// 重写 Object 类的 clone 方法,就可以让使用者,直接调用这个方法,完成对对象的克隆

@Override
public Phone clone() throws CloneNotSupportedException {
// Object类的 clone 方法默认实现了对对象的 浅克隆
// 把对象中的简单数据类型(8个基本数据类型和String)的数据复制1份放到新对象中,把引用数据数据类型,仅复制地址值,不赋值内容,放到新对象中
Phone clone = (Phone) super.clone();
// 针对,memory 再复制一份,把复制后的结果,交给 clone 对象保存
double[] clone1 = memory.clone();
clone.setMemory(clone1);
return clone;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class TestPhone {
public static void main(String[] args) throws CloneNotSupportedException {
// 1: 创建手机对象
Phone phone = new Phone("锤子",998,new double[]{8,12,16});

// 2: 需求: 把上面的对象复制一份新的对象出来,要达到对复制后的对象修改,不能影响老对象
//Phone p2 = phone; // 不能复制对象,仅仅是将对象的地址值(引用)复制了一份,在内存中还是只有一个对象
Phone p2 = phone.clone();
// 通过 p2 修改信息,
p2.setBrand("魅族");
p2.setPrice(2323);
p2.getMemory()[1]= 4;
System.out.println(p2);
System.out.println(phone);


}
}