誰動了我的乳酪?--java例項初始化的順序問題
阿新 • • 發佈:2019-09-14
故事背景
有一天,老鼠小白髮現了一個奇怪的問題,它的乳酪的生產日期被誰搞丟了,不知道乳酪是否過期,可怎麼吃呀?
讓我們來看看吧
import java.util.Date;
public class Cheese {
public static final Cheese cheese=new Cheese();
private final long produceTimes;
private static final long produceDate =new Date(119,8,1).getTime();
private Cheese() {
produceTimes=new Date().getTime()-produceDate;}
public long produceTimes() {
return produceTimes;
}
public static void main(String[] args) {
System.out.println("current time in day(from 1900:00:00) : "+new Date().getTime()/(1000*60*60*24L));
System.out.println("cheese had produces : "+ cheese.produceTimes()/(1000*60*60*24L) +" days");
}
}
按照小白的預期,程式該跑出乳酪上市了多少天,可是打印出的結果確實乳酪不會過期
current time in day(from 1900:00:00) : 18153
cheese had produces : 18153 days
這是怎麼回事呢?
破案
檢視程式碼提交記錄,發現老鼠小藍有修改記錄,僅僅調整了兩行程式的順序,小白原來的程式碼如下:
import java.util.Date;
public class Cheese {
private final long produceTimes;
private static final long produceDate =new Date(119,8,1).getTime();
public static final Cheese cheese=new Cheese();
private Cheese() {
produceTimes=new Date().getTime()-produceDate;
}
public long produceTimes() {
return produceTimes;
}
public static void main(String[] args) {
System.out.println("current time in day(from 1900:00:00) : "+new Date().getTime()/(1000*60*60*24L));
System.out.println("cheese had produces : "+ cheese.produceTimes()/(1000*60*60*24L) +" days");
}
}
僅僅修改了兩個變數的順序,輸出的結果就大相徑庭了
current time in day(from 1900:00:00) : 18153
cheese had produces : 13 days
這才是小白鼠想要的結果!
於是小白鼠去請教java的創造者java之父
原來,例項的初始化也是有講究的。
1.static欄位先設定預設值,其中cheese被設定為null,produceDate被設定為0
2.然後static初始器執行,按照宣告出現的順序執行:
如果先執行cheese的話,呼叫Cheese()構造方法,此時用produceDate=0為值。
如果先執行produceDate的話,producteDate被設定為2019-09-01,再呼叫cheese()構造方法。
3 最後從構造器返回cheese類的初始化。
說明
Date設定日期為2019-09-01 為何設定為
new Date(119,8,1)
大家可以進去原始碼看說明情況
/** * Allocates a <code>Date</code> object and initializes it so that * it represents midnight, local time, at the beginning of the day * specified by the <code>year</code>, <code>month</code>, and * <code>date</code> arguments. * * @param year the year minus 1900. * @param month the month between 0-11. * @param date the day of the month between 1-31. * @see java.util.Calendar * @deprecated As of JDK version 1.1, * replaced by <code>Calendar.set(year + 1900, month, date)</code> * or <code>GregorianCalendar(year + 1900, month, date)</code>. */ @Deprecated public Date(int year, int month, int date) { this(year, month, date, 0, 0, 0); }
其中,year份是從1900年開始的年數,即2019-1900=119
month是0~11計數的,需要實際月份減1,即9-1=8
date 是1~31計數的,實際天就可以 即1
參考資料
【1】https://docs.oracle.com/javase/specs/jls/se12/html/jls-12.html#jls-