4.2.3 更改器方法与访问器方法
现在,可能有人会问:如何从封装在某个GregorianCalendar对象内部的日期中获得当前的日、月、年呢?如果希望对这些内容做一些修改,又该怎么做呢?在联机文档中,以及本章末尾的API注释中可以找到答案。这里只讲述一些最重要的方法。
日历的作用是提供某个时间点的年、月、日等信息。要想查询这些设置信息,应该使用GregorianCalendar类的get方法。为了表达希望得到的项,需要借助于Calendar类中定义的一些常量,如:Calendar.MONTH或Calendar.DAY_OF_WEEK:
API注释列出了可以使用的全部常量。
调用set方法,可以改变对象的状态:
另外,还有一个便于设置年、月、日的方法,调用方式如下:
最后,还可以为给定的日期对象增加天数、星期数、月份等:
如果传递的数值是一个负数,日期就向前移。
get方法与set和add方法在概念上是有区别的。get方法仅仅查看并返回对象的状态,而set和add方法却对对象的状态进行修改。对实例域做出修改的方法称为更改器方法(mutator method),仅访问实例域而不进行修改的方法称为访问器方法(accessor method)。
C++注释:在C++中,带有const后缀的方法是访问器方法;默认为更改器方法。但是,在Java语言中,访问器方法与更改器方法在语法上没有明显的区别。
通常的习惯是在访问器方法名前面加上前缀get,在更改器方法前面加上前缀set。例如,在GregorianCalendar类有getTime方法和setTime方法,它们分别用来获得和设置日历对象所表示的时间点。
这两个方法在进行GregorianCalendar和Date类之间的转换时非常有用。这里有一个例子。假定已知年、月、日,并且希望创建一个包含这个时间值的Date对象。由于Date类不知道如何操作日历,所以首先需要构造一个GregorianCalendar对象,然后再调用getTime方法获得一个日期:
与之相反,如果希望获得Date对象中的年、月、日信息,就需要构造一个Gregorian-Calendar对象、设置时间,然后再调用get方法:
下面用一个应用GregorianCalendar类的程序来结束本节内容的论述。这个程序将显示当前月的日历,其格式为:
当前的日用一个*号标记。可以看到,这个程序需要解决如何计算某月份的天数以及一个给定日期相应是星期几。
下面看一下这个程序的关键步骤。首先,构造了一个日历对象,并用当前的日期和时间进行初始化。
两次调用get方法来获得当时的日、月。
然后,将d设置为这个月的第一天,并得到这一天为星期几。
如果这个月的第一天是星期日,变量weekday就设置为Calendar.SUNDAY;如果这个月的第一天是星期一,就设置为Calendar.MONDAY,以此类推(实际上,这些值是整数值1,2,...,7,但最好不要依赖背景知识写代码)。
注意,在日历的第一行是缩进的,因此,月份的第一天指向相应的星期几。由于把哪天当做一个星期的第一天有着不同的约定习惯,因此需要能够随机应变。在美国,每个星期的第一天是星期日;在欧洲,每个星期的第一天是星期一,最后一天是星期日。
Java虚拟机非常注意当前用户的所在地区,不同的地区存在着不同的格式习惯,包括每星期的起始日以及一星期中每天的命名方式。
提示:如果想看到不同地区程序的输出,应该在main方法的第一行中添加下列代码:
getFirstDayOfWeek方法获得当前地区星期的起始日。为了确定所需要的缩进距离,将日历对象的日减1,直到一个星期的第一天为止。
随后,输出表示星期几名称的前几个字母。这个操作可以通过调用DateFormatSymbols类方法实现。
getShortWeekdays方法返回用户语种所命名的表示星期几的缩写字符串(例如:英语将返回“Sun”、“Mon”等)。数组用星期数作为索引。下面的循环将打印星期几的缩写字符串:
现在,已经做好打印日历内容的准备了。第一行缩进,并将日期对象设置为月份的起始日。进入一个循环,其中用d记录一个月中的每一天。
在每次迭代过程中,打印日期值。如果d是当前日期,打印日期之后再打印一个*标记。每个星期的第一天,重新换行打印。而后,将d设置为下一天:
什么时候结束呢?我们并不知道这个月有几天,是31天、30天、29天,还是28天。实际上,只要d还指示当月就应该继续迭代。
一旦d进入下一个月,程序就终止执行。
程序清单4-1给出了完整的程序。
正如前面所看到的,日历程序包含了一些复杂问题,例如:某一天是星期几,每个月有多少天等。有了GregorianCalendar类一切就变得简单了。我们并不必知道GregorianCalendar类是如何计算星期数和每个月的天数,而只需要使用类提供的接口:get方法、set方法以及add方法就可以了。
这个示例程序的关键是:可以使用类的接口解决复杂任务,而不必知道其中的实现细节。
程序清单4-1 CalendarTest/CalendarTest.java
API java.util.GregorianCalendar 1.1
·GregorianCalendar()
构造一个日历对象,用来表示默认地区、默认时区的当前时间。
·GregorianCalendar(int year,int month,int day)
·GregorianCalendar(int year,int month,int day,int hour,int minutes,int seconds)
用给定的日期和时间构造一个Gregorian 日历对象。
参数:year 该日期所在的年份
month 该日期所在的月份,以0为基准;例如,0表示一月
day 该月份中的日期
hour 小时(0到23之间)
minutes 分钟(0到59之间)
seconds 秒(0到59之间)
·int get(int field)
返回给定域的值。
参数:field 可以是下述选项之一:Calendar.ERA、Calendar.YEAR、Calendar.MONTH、Calendar.WEEK_OF_YEAR、Calendar.WEEK_OF_MONTH、Calendar.DAY_OF_MONTH、Calendar.DAY_OF_YEAR、Calendar.DAY_OF_WEEK、Calendar.DAY_OF_WEEK_IN_MONTH、Calendar.AM_PM、Calendar.HOUR、Calendar.HOUR_OF_DAY、Calendar.MINUTE、Calendar.SECOND、Calendar.MILLISECOND、Calendar.ZONE_OFFSET、Calendar.DST_OFFSET
·void set(int field,int value)
设置特定域的值。
参数:field get接收的常量之一
value 新值
·void set(int year,int month,int day)
·void set(int year,int month,int day,int hour,int minutes,int seconds)
将日期域和时间域设置为新值。
参数:year 该日期所在的年份
month 该日期所在的月份。此值以0为基准;例如,0表示一月
day 该月份中的日期
hour 小时(0到23)
minutes 分钟(0到59)
seconds 秒(0到59)
·void add(int field,int amount)
这是一个可以对日期信息实施算术运算的方法。对给定的时间域增加指定数量的时间。例如,可以通过调用c.add(Calendar.DAY_OF_MONTH,7),将当前的日历日期加上7。
参数:field 需要修改的域(可以使用get方法文档中给出的一个常量)
amount 域被改变的数量(可以是负值)
·int getFirstDayOfWeek()
获得当前用户所在地区,一个星期中的第一天。例如:在美国一个星期中的第一天是Calendar.SUNDAY。
·void setTime(Date time)
将日历设置为指定的时间点。
参数:time 时间点
·Date getTime()
获得这个日历对象当前值所表达的时间点。
API java.text.DateFormatSymbols 1.1
·String[]getShortWeekdays()
·String[]getShortMonths()
·String[]getWeekdays()
·String[]getMonths()
获得当前地区的星期几或月份的名称。利用Calendar的星期和月份常量作为数组索引值。