30+的人學程式設計,使用預定義類(長文)
在Java中,沒有類就無法做任何事情,且並不是所有的類都具有物件導向的特徵,比如Math類。
1、物件與物件變數:
要想使用物件,就必須首先構造物件,並指定其初始狀態,然後,對物件應用方法;在Java中,
舉例說明:在Java類庫中有一個Date類,它的物件將描述一個時間點,比如:December 31,1999,23:59:59 GMT。
構造器的名字應該與類名相同,因此,Date類的構造器名為Date。要想構造一個Date物件,需要在構造器前面加上new操作符,如下所示:
new Date()
這個運算式構造了一個新物件,這個物件被初始化為當前的日期和時間。如果需要的話,也可以將這個物件傳遞給一個方法:
System.out.println(new Date());
或者,也可以將一個方法應用於剛剛創建的物件。如果希望構造的物件可以多次使用,我們需要將物件存放在一個變數中:
Date birthday = new Date();
創建一個新物件
在物件與物件變數之間存在著一個重要的區別,例如,語句:
Date deadline;
定義了一個物件變數deadline,它可以引用Date類型的物件,但是,一定要認識到,變數deadline不是一個物件,而且也沒有引用物件,這個時候,不能將任何Date方法應用於這個變數上,
deadline = new Date();
也可以讓這個變數引用一個已存在的物件;
deadline = birthday;
現在,這兩個變數引用同一個物件,如圖:
引用同一個物件的物件變數
一定要認識到:一個物件變數並沒有實際包含一個物件,而僅僅引用一個物件。
在Java中,任何物件變數的值都是對存儲在另外一個地方的一個物件的引用,new操作符的返回值也是一個引用。
2、Java類庫中的LocalDate類:
在前面的例子中,已經使用了Java標準類庫中的Date類。Date類的實例有一個狀態,即特定的時間點。
儘管在使用Date類時不必知道這一點,但時間是用距離一個固定時間點的毫秒數表示的,這個點就是所謂的紀元,它是UTC時間1970年1月1日00:00:00。
但是,Date類所提供的日期處理並沒有太大的用途,Java類庫的設計者認為:像Date這樣的日期只是西曆的固有習慣,像中國的農曆表示就很不一樣。
類庫的設計者決定將保存時間與給時間點命名進行分開,這樣,標準類庫分別包含了兩個類:一個是用來表示時間點的Date類,一個是用來表示大家熟悉的日曆標記法的LocalDate類。
將時間與日曆分開是一種很好的物件導向設計,通常最好使用不同的類表示不同的概念。
不要使用構造器來構造LocalDate類的物件,實際上,應當使用靜態工廠方法代表你調用構造器,下面的運算式:
LocalDate.now()
會構造一個新物件,表示構造這個物件時的日期。
可以提供年、月、日來構造對應一個特定日期的物件:
LocalDate.of(1999,12,31);
當然,通常都希望將構造的物件保存在一個物件變數中:
LocalDate newYearsEve = LocalDate.of(1999,12,31);
一時有了一個LocalDate物件,可以用方法getYear、getMonthValue、getDayOfMonth得到年月日:
int year = newYearsEve.getYear(); //1999
int month = newYearsEve.getMonthValue(); //12
int day = newYearsEve.getDayOfMonth(); //31
看起來,這樣寫代碼沒有什麼意義,因為這本來就是構造物件的那些值,不過關鍵的地方是,有時候那些日期或時間是通過計算得到的,所以才會有這種寫法。
3、更改器方法與訪問器方法:
再來看上一節中的plusDays方法調用:
LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);
這個調用之後newYearsEve會有什麼變化?它會改為1000天之後的日期嗎?事實上,並沒有。plusDays方法會生成一個新的LocalDate物件,然後把這個新物件賦給aThousandDaysLater變數,原來的物件不做任何改動,我們說plusDays方法沒有更改調用這個方法的物件。
在Java的較早版本中有一個名為:GregorianCalendar的類來處理日曆,可以為這個類表示的日期增加1000天:
GregorianCalendar someDay = new GregorianCalendar(1999,11,31);
someDay.add(Calendar.DAY_OF_MONTH);
與LocalDate.plusDays方法不同,GregorianCalendar.add方法是一個更改器方法,調用這個方法後,someDay物件的狀態會改變,可以如下查看新狀態:
year = someDay.get(Calendar.YEAR); //2002
month = someDay.get(Calendar.MONTH) + 1; //09
day = someDay.get(Calendar.DAY_OF_MONTH); //26
正是因為這個原因,我們將變數命名為someDay而不是newYearsEve,調用這個更改器方法之後,它不再是新年前夜。
相反,只訪問物件而不修改物件的方法有時稱為訪問器方法。
我們來寫個日曆吧:格式如下圖:
日曆
詳細的代碼如下:
代碼
可以看到,利用LocalDate類可以編寫一個日曆程式,能處理星期幾以及各月天數不同等複雜問題,你並不需要知道LocalDate類如何計算月和星期幾,只需要使用這個類的介面和方法。
再來看上一節中的plusDays方法調用:
LocalDate aThousandDaysLater = newYearsEve.plusDays(1000);
這個調用之後newYearsEve會有什麼變化?它會改為1000天之後的日期嗎?事實上,並沒有。plusDays方法會生成一個新的LocalDate物件,然後把這個新物件賦給aThousandDaysLater變數,原來的物件不做任何改動,我們說plusDays方法沒有更改調用這個方法的物件。
在Java的較早版本中有一個名為:GregorianCalendar的類來處理日曆,可以為這個類表示的日期增加1000天:
GregorianCalendar someDay = new GregorianCalendar(1999,11,31);
someDay.add(Calendar.DAY_OF_MONTH);
與LocalDate.plusDays方法不同,GregorianCalendar.add方法是一個更改器方法,調用這個方法後,someDay物件的狀態會改變,可以如下查看新狀態:
year = someDay.get(Calendar.YEAR); //2002
month = someDay.get(Calendar.MONTH) + 1; //09
day = someDay.get(Calendar.DAY_OF_MONTH); //26
正是因為這個原因,我們將變數命名為someDay而不是newYearsEve,調用這個更改器方法之後,它不再是新年前夜。
相反,只訪問物件而不修改物件的方法有時稱為訪問器方法。
我們來寫個日曆吧:格式如下圖:
日曆
詳細的代碼如下:
代碼
可以看到,利用LocalDate類可以編寫一個日曆程式,能處理星期幾以及各月天數不同等複雜問題,你並不需要知道LocalDate類如何計算月和星期幾,只需要使用這個類的介面和方法。