Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
目录
0.前言
1.TemporalAccessor源码
2.Temporal源码
3.TemporalAdjuster源码
4.ChronoLocalDate源码
5.LocalDate源码
6.总结
0.前言
通过前面Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中主要的类关系简图如下:

可以看出主要的LocalDate, LocalTime, LocalDateTime, Instant都是实现相同的接口,这里以LocalDate为例分析java8时间api源码,其他的类与LocalDate类似。
LocalDate的相关类图如下:完整类图

可以看出LocalDate同时实现了Temporal, TemporalAdjuster, ChronoLocalDate三个接口。
java.time包是在jdk8中上添加进来的,jdk8接口有了一些新的特性:接口的默认方法、静态方法和函数式接口。
接口的默认方法:使用default 关键字给接口增加非抽象的方法实现,子类可以选择性实现。
静态方法:接口里可以声明静态方法,并且可以实现。
函数式接口:增加@FunctionalInterface 注解,只要这个接口只包含一个抽象方法。
更多描述可以参考Java 8 指南:https://www.cnblogs.com/xkzhangsanx/p/10847284.html
1.TemporalAccessor源码

TemporalAccessor是框架级接口,定义对时态对象(如日期、时间、偏移量或它们的某些组合)的只读访问。
这是日期、时间和偏移量对象的基本接口类型。它是由那些可以提供信息的类实现的,比如{@linkplain TemporalField字段}或{@linkplain TemporalQuery查询}。
(1)boolean isSupported(TemporalField field)
检查是否支持指定的字段
(2)default ValueRange range(TemporalField field)
默认方法,获取指定字段的有效值范围
(3)default int get(TemporalField field)
这个方法为默认方法,以int的形式获取指定字段的值
(4)long getLong(TemporalField field)
以long的形式获取指定字段的值
(5)default <R> R query(TemporalQuery<R> query)
默认方法,这个日期-时间查询。它使用指定的查询策略对象查询此日期-时间。
2.Temporal源码

Temporal继承TemporalAccessor接口。
Temporal也是框架级接口,定义对时态对象(如日期、时间、偏移量或它们的某些组合)的读写访问。
这是日期、时间和偏移量对象的基本接口类型,这些对象足够完整,可以使用加减操作。
(1)boolean isSupported(TemporalUnit unit)
检查是否支持指定的单元
(2)default Temporal with(TemporalAdjuster adjuster)
默认方法,返回调整后的对象
例如:
date = date.with(lastDayOfMonth());
返回当前月的最后一天
(3)Temporal with(TemporalField field, long newValue)
根据指定的字段更改
(4)default Temporal plus(TemporalAmount amount)
默认方法,增加指定时间
(5)Temporal plus(long amountToAdd, TemporalUnit unit)
根据指定的单位增加时间
(6)default Temporal minus(TemporalAmount amount)
默认方法,减少指定时间
(7)default Temporal minus(long amountToSubtract, TemporalUnit unit)
默认方法,根据指定的单元减少时间
(8)long until(Temporal endExclusive, TemporalUnit unit)
根据指定的单元计算到另一个时间的相差值
例如:
LocalDate localDate = LocalDate.of(2019, 1, 1);
LocalDate endDate = LocalDate.of(2019, 1, 16);
long days = localDate.until(endDate, ChronoUnit.DAYS);
System.out.println(days);
输出:15
3.TemporalAdjuster源码

TemporalAdjuster接口加了函数式接口@FunctionalInterface注解,用于调整时间对象的策略。
(1)Temporal adjustInto(Temporal temporal)
调整指定的时间对象。
java.time.temporal.TemporalAdjusters 为常用的时间调节器,包含当月第一天,最后一天等等。

方法说明:
dayOfWeekInMonth 同一个月中每一周的第几天
firstDayOfMonth 当月的第一天
firstDayOfNextMonth 下月的第一天
firstDayOfNextYear 明年的第一天
firstDayOfYear 当年的第一天
firstInMonth 同一个月中,第一个符合星期几要求的值
lastDayOfMonth 当月的最后一天
lastDayOfNextMonth 下月的最后一天
lastDayOfNextYear 明年的最后一天
lastDayOfYear 今年的最后一天
lastInMonth 同一个月中,最后一个符合星期几要求的值
next/previous 将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期
nextOrSame/previousOrSame 将其值设定为日期调整后或者调整前,第一个符合指定星
期几要求的日期,如果该日期已经符合要求,直接返回该对象
例如:当月最后一天
temporal = temporal.with(lastDayOfMonth());
4.ChronoLocalDate源码
ChronoLocalDate 接口 继承了Temporal, TemporalAdjuster, Comparable<ChronoLocalDate>接口。
在任意年表中不包含(时间或时区)的日期,用于高级全球化用例。

从图中圈中部分可以看出 ChronoLocalDate实现了实现或重写了Temporal, TemporalAdjuster, Comparable<ChronoLocalDate>接口。
其他方法:
(1)default boolean isLeapYear()
默认方法,计算闰年
(2)int lengthOfMonth()
根据日历系统的定义,返回由这个日期表示的月份的长度。
(3)default int lengthOfYear()
默认方法,返回由日历系统定义的日期表示的年份长度。
(4)default long toEpochDay()
默认方法,返回1970-01-01开始的天数
(5)default int compareTo(ChronoLocalDate other)
默认方法,实现接口Comparable,比较大小
(6)default boolean isAfter(ChronoLocalDate other)
是否在other后面
(7)default boolean isBefore(ChronoLocalDate other)
是否在other前面
(8)default boolean isEqual(ChronoLocalDate other)
是否与other相等
(9)object接口相关的方法:
boolean equals(Object obj)
int hashCode()
String toString()
(10)static ChronoLocalDate from(TemporalAccessor temporal)
从时态对象获取ChronoLocalDate的实例。
(11)default ChronoLocalDateTime<?> atTime(LocalTime localTime)
将这个日期和时间组合起来,创建一个ChronoLocalDateTime。
(12)default String format(DateTimeFormatter formatter)
ChronoLocalDate 格式化处理
(13)Chronology getChronology()
获取此日期的年表
(14)default Era getEra()
获取由年表定义的年代
5.LocalDate源码
LocalDate同时实现了Temporal, TemporalAdjuster, ChronoLocalDate三个接口,是ChronoLocalDate接口国际化的ISO-8601标准实现,final修饰,线程安全,方法特别多,但很有规律。
类图如下:

主要属性为:
/**
*最小日期:-999999999-01-01
*/
public static final LocalDate MIN = LocalDate.of(Year.MIN_VALUE, 1, 1); /**
*最d大日期:+999999999-12-31
*/
public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31); /**
*400年周期中的天数
*/
private static final int DAYS_PER_CYCLE = 146097; /**
*从0年到1970年的天数
*/
static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
/**
*年
*/
private final int year;
/**
*月
*/
private final short month;
/**
*日
*/
private final short day;
主要方法,除了实现Temporal, TemporalAdjuster, ChronoLocalDate三个接口还添加了一些特有的方法。所有可以分为6类方法:
(1)创建LocalDate对象方法

例如:创建当前日期:
LocalDate now = LocalDate.now();
源码:可以看出是使用系统默认的Clock创建当前日期的。
public static LocalDate now() {
return now(Clock.systemDefaultZone());
}
(2)获取属性方法

例如:获取年
int year = now.getYear();
源码:直接获取属性中year
public int getYear() {
return year;
}
(3)修改属性的方法

例如:修改年,输出:2020-12-26
LocalDate localDate1 = now.withYear(2020);
System.out.println(localDate1);
源码:可以看到底层,return new LocalDate(year, month, day); 创建了一个新对象。
public LocalDate withYear(int year) {
if (this.year == year) {
return this;
}
YEAR.checkValidValue(year);
return resolvePreviousValid(year, month, day);
}
private static LocalDate resolvePreviousValid(int year, int month, int day) {
switch (month) {
case 2:
day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
break;
case 4:
case 6:
case 9:
case 11:
day = Math.min(day, 30);
break;
}
return new LocalDate(year, month, day);
}
(4)增加或减少日期方法

例如:减少1年,输出:2018-12-26
LocalDate localDate2 = now.minusYears(1);
System.out.println(localDate2);
源码:可以看出底层使用了:plusYears(-yearsToSubtract),相当于+(-1)
public LocalDate minusYears(long yearsToSubtract) {
return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
}
(5)转换为各类DateTime(LocalDateTime、ZonedDateTime和OffsetDateTime)方法

例如:转为LocalDateTime 输出为:2019-12-26T00:00
LocalDateTime localDateTime = now.atStartOfDay();
System.out.println(localDateTime);
源码:this为当前的日期,LocalTime.MIDNIGHT为零点时间,组合为为LocalDateTime
public LocalDateTime atStartOfDay() {
return LocalDateTime.of(this, LocalTime.MIDNIGHT);
}
(6)其他方法主要为实现ChronoLocalDate定义的方法
例如:ChronoLocalDate中定义的判断和比较方法

6.总结
TemporalAccessor主要定义了只读的获取属性方法,Temporal主要定义了修改日期属性和日期加减运算方法,ChronoLocalDate定义了国际化lDate的通用方法,LocalDate是ChronoLocalDate的ISO标准实现,实现了上述所有接口,final修饰,线程安全,方法定义明确,丰富多样,适用广。
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析的更多相关文章
- netty中的发动机--EventLoop及其实现类NioEventLoop的源码分析
EventLoop 在之前介绍Bootstrap的初始化以及启动过程时,我们多次接触了NioEventLoopGroup这个类,关于这个类的理解,还需要了解netty的线程模型.NioEventLoo ...
- 🏆【Alibaba中间件技术系列】「RocketMQ技术专题」让我们一起探索一下DefaultMQPushConsumer的实现原理及源码分析
RocketMQ的前提回顾 RocketMQ是一款分布式.队列模型的消息中间件,具有以下特点: 能够保证严格的消息顺序 提供丰富的消息拉取模式 高效的订阅者水平扩展能力 实时的消息订阅机制 亿级消息堆 ...
- java String类 trim() 方法源码分析
public String trim() { int arg0 = this.value.length; //得到此字符串的长度 int arg1 = 0; //声 ...
- Servlet容器Tomcat中web.xml中url-pattern的配置详解[附带源码分析]
目录 前言 现象 源码分析 实战例子 总结 参考资料 前言 今天研究了一下tomcat上web.xml配置文件中url-pattern的问题. 这个问题其实毕业前就困扰着我,当时忙于找工作. 找到工作 ...
- Java线程池ThreadPoolExector的源码分析
前言:线程是我们在学习java过程中非常重要的也是绕不开的一个知识点,它的重要程度可以说是java的核心之一,线程具有不可轻视的作用,对于我们提高程序的运行效率.压榨CPU处理能力.多条线路同时运行等 ...
- 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位 | 百篇博客分析OpenHarmony源码 | v35.02
百篇博客系列篇.本篇为: v35.xx 鸿蒙内核源码分析(时间管理篇) | 谁是内核基本时间单位 | 51.c.h .o 本篇说清楚时间概念 读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇. 时间 ...
- ABP源码分析四十五:ABP ZERO中的EntityFramework模块
AbpZeroDbContext:配置ABP.Zero中定义的entity的Dbset EntityFrameworkModelBuilderExtensions:给PrimitiveProperty ...
- heapster源码分析——kubelet的api调用分析
一.heapster简介 什么是Heapster? Heapster是容器集群监控和性能分析工具,天然的支持Kubernetes和CoreOS.Kubernetes有个出名的监控agent---cAd ...
- Vue3中的响应式对象Reactive源码分析
Vue3中的响应式对象Reactive源码分析 ReactiveEffect.js 中的 trackEffects函数 及 ReactiveEffect类 在Ref随笔中已经介绍,在本文中不做赘述 本 ...
随机推荐
- node安装升级过程中遇到的问题汇总
一.Node already installed, it's just not linked 第一步:sudo chown -R $(whoami) $(brew --prefix)/* 第二步:br ...
- ASP.NET + MVC5 入门完整教程三 (下) ---MVC 松耦合
建立松耦合组件 MVC 模式最重要的特性之一视他支持关注分离,希望应用程序中的组件尽可能独立,只有很少的几个可控依赖项.在理想的情况下,每个组件都不了解其他组件,而只是通过抽象接口来处理应用程序的其他 ...
- HTML的媒体元素(视频+音频)
网页的媒体元素 包括 视频 音频 首先创建一个文件夹,放视频和音频 播放(非自动播放+自动播放) 视频播放 1.1. 打开网页不自动播放 <video src="../ ...
- 2.2 logistic回归损失函数(非常重要,深入理解)
上一节当中,为了能够训练logistic回归模型的参数w和b,需要定义一个成本函数 使用logistic回归训练的成本函数 为了让模型通过学习来调整参数,要给出一个含有m和训练样本的训练集 很自然的, ...
- AcWing 896. 最长上升子序列 II
#include<iostream> #include<algorithm> #include<vector> using namespace std; int m ...
- 使用命令行生成动态库dll
1.安装开发工具,比如visual studio或者mingw等等.下面以visual studio编译器cl作为讲解. 2.导出dll中的函数基本使用两种方式,可以使用关键字__declspec(d ...
- 项目中的process.bpmn的读-过程
1.这次项目中遇到了process.bpmn类的封装好的类.怎么读呢?不知道,一周过去了,总算明白点. 2.首先也是从Controller开始,走进service层,比如mybatis,调用的就不是m ...
- 问题 D: 家庭问题
问题 D: 家庭问题 时间限制: 1 Sec 内存限制: 128 MB[命题人:admin] 题目描述 有n个人,编号为1,2,……n,另外还知道存在K个关系.一个关系的表达为二元组(α,β)形式, ...
- 使用Eclipse远程调试云服务器上的微信公众项目
云服务器系统:centos 7.3 如何在Eclipse上调试我们在云服务器上的项目呢,下面介绍一下步骤: 1.因为root账号不支持远程调试,首先需要在linux上创建一个新的用户,然后用该用户 ...
- dw 快捷键
<html></html> 创建一个HTML文档<head></head> 设置文档标题和其它在网页中不显示的信息<title></t ...