最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解決Java Calendar類set()方法的陷阱

 更新時間:2020年03月02日 09:51:08   作者:freelk  
這篇文章主要介紹了解決Java Calendar類set()方法的陷阱,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

在項目中,需要獲取指定年份和月份的最后一天。我在網(wǎng)上找到了一個用Calendar類獲取的方法,代碼如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
 
public class TestCalendar {
	public static void main(String[] args) {
		String s = new SimpleDateFormat("yyyy-MM-dd")
				.format(getLastDay(2017, 9));
		System.out.println(s);
	}
 
	public static Date getLastDay(int year, int month) {
		//獲取Calendar類的實例
		Calendar c = Calendar.getInstance();
		//設置年份
		c.set(Calendar.YEAR, year);
		//設置月份,因為月份從0開始,所以用month - 1
		c.set(Calendar.MONTH, month - 1);
		//獲取當前時間下,該月的最大日期的數(shù)字
		int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
		//將獲取的最大日期數(shù)設置為Calendar實例的日期數(shù)
		c.set(Calendar.DAY_OF_MONTH, lastDay);
 
		return c.getTime();
	}
}

剛開始使用這個方法的時候,很正常。后來在10月31號(這個日期很重要)當天測試的時候,傳遞的參數(shù)時2017年9月,即上面的代碼,但是結果卻出現(xiàn)的了問題,結果如下圖:

本來該是2017-09-30,可是結果卻是2017-10-01,我原先測試過,這個方法是沒有問題的,可是出了這樣的問題。后來我斷點測試,在剛獲取到Calendar實例的時候,實例中的字段值如下圖:

但是發(fā)現(xiàn)在執(zhí)行完

c.set(Calendar.MONTH, month - 1);

這行的代碼的時候,Calendar的實例中,MONTH字段的值不是我預想中的8(月份字段從0開始),而是9,而且DAY_OF_MONTH字段的值從31變成了1,如下圖所示:

因此,可以判斷Calendar實例獲取到的時候,是10月31號,實例中的DAY_OF_MONTH的值是31,當把MONTH字段的值設置為8后,因為9月份只有30天,那DAY_OF_MONTH的值就多1,會自動向后順延1天,變成了2017-10-01 。

但是,還是有其他的問題,因為下面還執(zhí)行了

c.set(Calendar.DAY_OF_MONTH, lastDay);

這句代碼,最后的日期應該是2017-10-31才對,但是run的結果卻是2017-10-01,debug的結果是2017-10-31 。

我第一感覺認為Calendar類是不是存在線程安全問題,可是后來一想就覺得不對,畢竟我只是在主線程中運行,沒有多線程,并不存在這個問題。

第二天我又嘗試了下,發(fā)現(xiàn)了問題的原因,如上面的最后一張圖所示,在debug的過程中,我用IDEA的watches功能查看了Calendar實例的字段值,用了get()方法,如果我刪除掉這幾個get方法之后,發(fā)現(xiàn)run和debug的值是一樣的,都是2017-10-01,說明問題出在get()方法上。

因此,可以做如下修改:

在代碼中,直接打印變量c的值,可以發(fā)現(xiàn),在調用get()方法之前,變量c的各字段值是set()方法設置的,但是并沒有對其進行驗證計算,在調用get()方法的過程中,會對各字段驗證計算。我查看了部分源碼,在調用get(),add(),getTime()等方法的過程中,底層都會調用computeTime()方法,對各字段的時間驗證計算。

另外,又做了一個demo測試,以佐證上面的結論,如下:

import java.text.SimpleDateFormat;
import java.util.Calendar;
 
public class TestCalendar2 {
 
	public static void main(String[] args) {
		Calendar c = Calendar.getInstance();
		c.set(Calendar.MONTH, 8);      //將月份設置為9月
		c.set(Calendar.DAY_OF_MONTH, 32);  //將日期設置為32
		System.out.println(c);       //直接打印Calendar實例,不使用getTime()方法
		c.get(Calendar.MONTH);
		System.out.println(c);
	}
}

結果如下:

即使設置的DAY_OF_MONTH值是明顯非法的,但是并不會在調用get()方法之前進行計算進位。

在查詢問題的過程中,也看到了其他的一些問題,下面對add(),set(),roll()方法的區(qū)別做了解釋:

示例代碼:

Calendar c = Calendar.getInstance();
 
c.set(2014, Calendar.MARCH, 31);
c.add(Calendar.MONTH, 13);
System.out.println(c.getTime());// 2015-04-30

 
c.set(2014, Calendar.MARCH, 31);
c.set(Calendar.MONTH, c.get(Calendar.MONTH) + 13);
System.out.println(c.getTime());// 2015-05-01

 
c.set(2014, Calendar.MARCH, 31);
c.roll(Calendar.MONTH, 13);
System.out.println(c.getTime());//2014-04-30

ADD方法

    以調整的單位為基點(本例中為月),較大的單位(年)會發(fā)生借位、進位。 較小的單位會往小調整。
    本例中,2014-03-31,加上13個月,年份會進位為2015年。 4月31日是不存在的,所以往小調整為4月30日。
    比較典型的運用場景是,日歷的按月切換。
    當前日期為2014-03-31,點擊【下一月】按鈕時,日期會變成2014-04-30.

SET方法

    所有的單位都會往大調整。
    本例中,2014-03-31,加上13個月,年份會進位為2015年。 4月31日是不存在的,所以往大調整為5月1日

ROLL方法

    以調整的單位為基點(本例中為月),較大的單位(年)不會發(fā)生改變。 較小的單位會往小調整。
    本例中,2014-03-31,加上13個月,年份依然為2014年。 4月31日是不存在的,所以往小調整為4月30日。
    日會根據(jù)年、月來判斷出日的取值范圍,然后在1~31之間無限循環(huán)滾動,但并不會影響到年、月的值。

總結三點:

 1、add() 有兩條規(guī)則:
 a)當被修改的字段超出它的取值范圍時,那么比它大的字段會自動修正。
 b)如果比它小的字段是不可變的/不在取值范圍內(由 Calendar 的實現(xiàn)類決定),那么該小字段會修正到變化最小的值。
 2、Roll() 的規(guī)則只有第二條
  當被修改的字段超出它的取值范圍時,那么比它大的字段不會被修正。比它小的字段會修正到變化最小的值。
 3、Set()
  比被修改的字段大的字段會根據(jù)字段是增大還是減小自動改變大小,比被修改字段小的字段如果是不可變的/不在取值范圍內,會自動增大到變化最小的值。

回到最初的問題,獲取指定年份和月份的最大的日期的方法要怎么辦?

方法可以改為:

public static Date getLastDay(int year, int month) {
	Calendar c = Calendar.getInstance();  //獲取Calendar類的實例
	c.clear();
	c.set(Calendar.YEAR, year);       //設置年份
	c.set(Calendar.MONTH, month - 1);    //設置月份,因為月份從0開始,所以用month - 1
	int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);  //獲取當前時間下,該月的最大日期的數(shù)字
	c.set(Calendar.DAY_OF_MONTH, lastDay); //將獲取的最大日期數(shù)設置為Calendar實例的日期數(shù)
	return c.getTime();           //返回日期
}

用clear()方法,將Calendar實例的字段和時間都設置為未定義,這樣可以解決這個問題。

當然網(wǎng)上也有將月份設置為下個月,然后用add(Calendar.DAY_OF_MONTH, -1)這樣的方法也可以得到結果,不過這里就不詳細介紹了。

到此這篇關于解決Java Calendar類set()方法的陷阱的文章就介紹到這了,更多相關Java Calendar set()內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java springboot接口迅速上手,帶你半小時極速入門

    Java springboot接口迅速上手,帶你半小時極速入門

    這篇文章主要給大家介紹了關于SpringBoot實現(xiàn)API接口的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-09-09
  • springboot 2.x整合mybatis實現(xiàn)增刪查和批量處理方式

    springboot 2.x整合mybatis實現(xiàn)增刪查和批量處理方式

    這篇文章主要介紹了springboot 2.x整合mybatis實現(xiàn)增刪查和批量處理方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 關于mybatis3中幾個@Provider的使用方式

    關于mybatis3中幾個@Provider的使用方式

    這篇文章主要介紹了關于mybatis3中幾個@Provider的使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • MyBatis typeAliases元素標簽(含注解方式)及其屬性、設置方式

    MyBatis typeAliases元素標簽(含注解方式)及其屬性、設置方式

    這篇文章主要介紹了MyBatis typeAliases元素標簽(含注解方式)及其屬性、設置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • JVM(Java虛擬機)簡介(動力節(jié)點Java學院整理)

    JVM(Java虛擬機)簡介(動力節(jié)點Java學院整理)

    Java虛擬機(Jvm)是可運行Java代碼的假想計算機。Java虛擬機包括一套字節(jié)碼指令集、一組寄存器、一個棧、一個垃圾回收堆和一個存儲方法域。對java jvm 虛擬機感興趣的朋友通過本文一起學習吧
    2017-04-04
  • vue 實現(xiàn)刪除對象的元素 delete

    vue 實現(xiàn)刪除對象的元素 delete

    這篇文章主要介紹了vue 實現(xiàn)刪除對象的元素delete,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • 使用idea+gradle編譯spring5.x.x源碼分析

    使用idea+gradle編譯spring5.x.x源碼分析

    這篇文章主要介紹了idea?+?gradle編譯spring5.x.x源碼,在編譯spring5源碼時需要將項目導入idea中然后編譯配置,本文給大家講解的非常詳細,需要的朋友可以參考下
    2022-04-04
  • SpringBoot中controller深層詳細講解

    SpringBoot中controller深層詳細講解

    這篇文章主要介紹了SpringBoot在Controller層接收參數(shù)的常用方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-02-02
  • SpringBoot中事務失效的原因詳解

    SpringBoot中事務失效的原因詳解

    這篇文章主要介紹了SpringBoot中事務失效的原因詳解,spring中的事務是依賴AOP的,AOP是通過動態(tài)代理實現(xiàn)的,只有通過代理類訪問的方法才能被攔截,需要的朋友可以參考下
    2023-10-10
  • 深入理解Java中的String(示例詳解)

    深入理解Java中的String(示例詳解)

    文章詳細介紹了Java中String類的特點、用途、主要方法以及常見用法,String類是不可變的,具有字符串常量池,特定的內存結構,并隨JDK版本更新而優(yōu)化,它廣泛用于表示和處理文本數(shù)據(jù),并在內存管理和性能優(yōu)化方面表現(xiàn)出色,感興趣的朋友一起看看吧
    2025-03-03

最新評論

四子王旗| 曲松县| 邛崃市| 梁山县| 从江县| 崇仁县| 广州市| 山西省| 五莲县| 新源县| 江孜县| 博爱县| 永和县| 大邑县| 肃北| 抚远县| 平安县| 普安县| 阿瓦提县| 宁化县| 八宿县| 原平市| 绍兴市| 天台县| 托克托县| 集安市| 新郑市| 师宗县| 从江县| 日照市| 阿鲁科尔沁旗| 长岛县| 姜堰市| 灵璧县| 青神县| 高邮市| 瑞金市| 尚义县| 南乐县| 泸西县| 台中县|