Jdk8中java.time包中的新的日期時間API類的LocalDate源碼分析,TemporalAccessor、Temporal、TemporalAdjuster、ChronoLocalDate和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修飾,線程安全,方法定義明確,豐富多樣,適用廣。