8、Java基础---创建日期类

创建日期类

一、日期类

日期是通过年、月、日这三项来表示的。我们来创建一个日期类,将这些项定义为int型字段;如果将类命名为Day, 只考虑字段的话,可以像下面这样进行声明;类Day的内容如图所示:

将所有的字段都设为私有(private) 外部访问可以通过构造函数和方法间接执行。

二、构造函数和方法

构造函数是在创建实例时为了正确进行初始化而设置的控件;类Day的构造函数的定义如下所示,形参中接收到的三个整数值直接赋给了各个字段;

为了访问与形参同名的字段,这里使用了this,如果不使用this, 则会变成:

在创建类Day类型的实例时,要传递给该构造函数三个int型的参数,如下所示:

Day birthday = new Day(1963, 11, 18);

启动构造函数时,birthday的字段year、manth、date就会被分别赋入1963 、11 、18;创建完构造函数后,下面创建如下所示的方法:

class Day {
	private int year;			// 年
	private int month;			// 月
	private int date;			// 日

	//--- 构造函数 ---//
	Day(int year, int month, int date) {
		this.year  = year;		// 年	
		this.month = month;		// 月
		this.date  = date;		// 日
	}

	//--- 获取年、月、日 ---//
	int getYear()  { return year; }		// 获取年
	int getMonth() { return month; }	// 获取月
	int getDate()  { return date; }		// 获取日

	//--- 设置年、月、日 ---//
	void setYear(int year)   { this.year  = year; }		// 设置年
	void setMonth(int month) { this.month = month; }	// 设置月
	void setDate(int date)   { this.date  = date; }		// 设置日

	void set(int year, int month, int date) {			// 设置年月日
		this.year  = year;			// 年	
		this.month = month;			// 月
		this.date  = date;			// 日
	}

	//--- 计算星期 --//
	int dayOfWeek() {
		int y = year;					// 0 … 星期日
		int m = month;					// 1 … 星期一
		if (m == 1 || m == 2) {			//  :
			y--;						// 5 … 星期五
			m += 12;					// 6 … 星期六
		}
		return (y + y / 4 - y / 100 + y / 400 + (13 * m + 8) / 5 + date) % 7;
	}
}

方法dayOfWeek会计算并返回星期的整数值如果是星期日,则返回值为0; 如果是星期一则返回值为1; 以此类推,如果是星期六则返回值为6。

三、访问器

//--- 获取年、月、日 ---//
	int getYear()  { return year; }		// 获取年
	int getMonth() { return month; }	// 获取月
	int getDate()  { return date; }		// 获取日

	//--- 设置年、月、日 ---//
	void setYear(int year)   { this.year  = year; }		// 设置年
	void setMonth(int month) { this.month = month; }	// 设置月
	void setDate(int date)   { this.date  = date; }		// 设置日

 

用于获取字段值的方法称为getter方法,用于设置字段值的方法称为setter方法,两者统称为访问器; 

使用类Day的程序示例:

import java.util.Scanner;

class DayTester {

	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);
		String[] wd = {"日", "一", "二", "三", "四", "五", "六"};

		System.out.println("请输入阳历生日。");
		System.out.print("年:");  int y = stdIn.nextInt();
		System.out.print("月:");  int m = stdIn.nextInt();
		System.out.print("日:");  int d = stdIn.nextInt();

		Day birthday = new Day(y, m, d);

		System.out.println("你的生日"
							 + birthday.getYear()  + "年"
							 + birthday.getMonth() + "月"
							 + birthday.getDate()  + "日是星期"
							+ wd[birthday.dayOfWeek()] + "。");
	}
}

输出:

四、类类型变量的赋值

// 类类型变量的赋值
class DayAssign {
    public static void main(String[] args) {
        Scanner stdIn = new Scanner(System.in);
        String[] wd = {"日", "一", "二", "三", "四", "五", "六"};
        System.out.println("请输入阳历生日。");
        System.out.print("年:");  int y = stdIn.nextInt();
        System.out.print("月:");  int m = stdIn.nextInt();
        System.out.print("日:");  int d = stdIn.nextInt();
        Day birthday = new Day(y, m, d);
        System.out.println("你的生日"
                + birthday.getYear()  + "年"
                + birthday.getMonth() + "月"
                + birthday.getDate()  + "日是星期"
                + wd[birthday.dayOfWeek()] + "。");
        Day xDay = birthday;
        xDay.set(2100, 12, 31);		// 设置为2100年12月31日
        System.out.println("birthday = "
                + birthday.getYear()  + "年"
                + birthday.getMonth() + "月"
                + birthday.getDate()  + "日("
                + wd[birthday.dayOfWeek()] + ")");

        System.out.println("xDay     = "
                + xDay.getYear()  + "年"
                + xDay.getMonth() + "月"
                + xDay.getDate()  + "日("
                + wd[xDay.dayOfWeek()] + ")");
    }
}

输出:

在上述程序中,另外创建了一个Day类型的变量xDay,并将其设置为2100年12月3l日,但这样一来,本不应该被设置值的birday的日期也被改写了我们来分析一下原因:

 Day xDay = birthday;

Day类型的变量xDay的声明,初始值birthday是类类型变量,是实例主体的引用。因此,xDay会被初始化为birthday实例的引用。最终,如图所示,遥控器birthday和xDay操作的对象(引用目标)实例是同一个实例。由于未调用函数, 因此肯定不会创建新的日期实例。

xDay.set(2100, 12, 31);		// 设置为2100年12月31日

中使用方法set将xDay的各个字段设置为2100、12 、31。对xDay引用的实例设置值其实就是修改原本为birthday创建的实例的值

当将类类型的变量初始化或者赋值为同一类型的变量时,会复制引用目标,而不会复制所有字段的值。

五、类类型变量的比较

对类类型变量应用的相等运算符==和!=会判断引用目标是否相同, 而不会判断字段的值是否相等

创建一个判断两个日期是否相等的程序:

class DayComparator1 {
	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);
		int y, m, d;
		System.out.println("请输入日期1。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day day1 = new Day(y, m, d);
		System.out.println("请输入日期2。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day day2 = new Day(y, m, d);
		if (day1 == day2)
			System.out.println("相等。");
		else
			System.out.println("不相等。");
	}
}

输出:

程序中的if语句会判断dayl和day2的引用目标是否相同。由于dayl和day2是分别创建的实例,因此它们的引用目标不相同,不管字段为何值,==运算符的结果永远都是false

若要判断所有字段的值是否相等,就需要调用getter 方法,确认年、月、日, 正确的程序如下:

class DayComparator2 {
	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);
		int y, m, d;
		System.out.println("请输入日期1。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day day1 = new Day(y, m, d);
		System.out.println("请输入日期2。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day day2 = new Day(y, m, d);
		if (day1.getYear() == day2.getYear() && day1.getMonth() == day2.getMonth()
									 && day1.getDate()  == day2.getDate())
			System.out.println("相等。");
		else
			System.out.println("不相等。");
	}
}

输出:

六、作为参数的类类型变量

创建一个判断两个日期是否相等的方法,程序就会变得更加简洁,这样改良后的程序如下:

class DayComparator3 {

	//--- d1和d2的日期相等吗? ---//
	static boolean compDay(Day d1, Day d2) {
		return d1.getYear()  == d2.getYear() &&
				 d1.getMonth() == d2.getMonth() &&
				 d1.getDate()  == d2.getDate();
	}

	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);

		int y, m, d;
		System.out.println("请输入日期1。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day day1 = new Day(y, m, d);

		System.out.println("请输入日期2。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day day2 = new Day(y, m, d);

		if (compDay(day1, day2))
			System.out.println("相等。");
		else
			System.out.println("不相等。");
	}
}

输出:

方法compDay是在类Day的外部声明的,请注意如下3点:

1)接收类类型的参数

形参d1和d2是Day类型的类类型变量,如图所示这两个形参按收的是Day类型实例的引用。因此,d1会引用day1的实例,d2会引用day2的实例。

2)声明中加上了static

由于本方法定义在类Day的外部,因此它不属于各个实例(day1或day2),加上static进行声明的方法就是类方法。

3)无法访问私有字段

由于本方法定义在类Day的外部,因此无法直接访问日期的字段year、month、date。本方法中通过调用getter方法getYear、getMonth、getDate来确认年、月、日的值。

if (compDay(day1, day2))

调用方法compDay ,将dayl实例的引用和day2实例的引用作为实参传递给该方法;if语句中根据方法的boolean型返回值,会分别显示”相等” 或“不相等”。

七、类类型实例的数组

创建一个Day类型实例的数组,程序会创建一个数组, 其元素个数通过键盘输入,并将全部元素的日期都设置为2017年IO月15日, 然后将其显示出来。

// 日期类Day的数组(运行时错误)

import java.util.Scanner;

class DayArrayError {

	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);
		String[] wd = {"日", "一", "二", "三", "四", "五", "六"};

		System.out.print("日期个数:");
		int n = stdIn.nextInt();

		Day[] a = new Day[n];			// 元素个数为n的Day类型数组

		for (int i = 0; i < a.length; i++)
			a[i].set(2017, 10, 15);		// 将全部元素都设置为2017年10月15日

		for (int i = 0; i < a.length; i++)
			System.out.println("a[" + i + "] = "
									 + a[i].getYear()  + "年"
									 + a[i].getMonth() + "月"
									 + a[i].getDate()  + "日("
									 + wd[a[i].dayOfWeek()] + ")");
	}
}

输出:

运行时.,在读入日期个数n之后就会发生运行时错误;

 Day[] a = new Day[n];			// 元素个数为n的Day类型数组

上述代码已经为a创建了数组主体,那为什么还会发生错误呢?

元素a[1]是引用Day的类类型变量(遥控器),不是日期的实例(主体) 当然、a[0] 和a[2] 也是如此

数组a并不是日期主体的数组,而是3个遥控器的集合数组。创建数组时,各个元素会被初始化为null;

for (int i = 0; i < a.length; i++)
            a[i].set(2017, 10, 15);		// 将全部元素都设置为2017年10月15日

上述执行会发生错误,因为此处对无任何引用的空引用a[i]调用了方法set。对于各个日期实例, 在类类型变量之外,还需要再使用new运算符来另外创建; 正确的程序如下所示:

for (int i = 0; i < a.length; i++)
a[i] = new Day(2017, 10, 15); 

输出:为了使用类类型实例的数组,必须在创建类类型变量的数组的基础上,再创建各个元素的实例。

将for语句的执行内容展开后如图所示,每次循环时都会创建Day类型实例,并将其初始化为2017年10月15日。然后,使用赋值运符符将创建的实例的引用赋给a[i].。

八、日期类的改进

创建了使用日期类的程序,但该程序中还存在不少的问题:
1)由于构造函数中需要三个int型参数,因此在创建实例时缺乏灵活性。 例如,在创建数组时就不可以 “不直接设性值,而先创建元素,然后再设置值”;
2)不易于构建与某个日期相同的日期实例;
3)不易于判断两个日期是否相等;
4)显示日期时需要3~4行的程序。

修改后代码如下:

public class Day {
	private int	year;		// 年
	private int	month;		// 月
	private int	date;		// 日

	//--- 构造函数 ---//
	public Day()                              { set(1, 1, 1); }
	public Day(int year)                      { set(year, 1, 1); }
	public Day(int year, int month)           { set(year, month, 1); }
	public Day(int year, int month, int date) { set(year, month, date); }
	public Day(Day d)                         { set(d.year, d.month, d.date); }

	//--- 获取年、月、日 ---//
	public int getYear()  { return year; }	// 年
	public int getMonth() { return month; }	// 月
	public int getDate()  { return date; }	// 日

	//--- 设置年、月、日 ---//
	public void setYear(int year)   { this.year  = year; }	// 年
	public void setMonth(int month) { this.month = month; }	// 月
	public void setDate(int date)   { this.date  = date; }	// 日

	public void set(int year, int month, int date) {		// 年月日
		this.year  = year;			// 年	
		this.month = month;			// 月
		this.date  = date;			// 日
	}

	//--- 计算星期 ---//
	public int dayOfWeek() {
		int y = year;					// 0 … 星期日
		int m = month;					// 1 … 星期一
		if (m == 1 || m == 2) {		    //  :
			y--;						// 5 … 星期五
			m += 12;					// 6 … 星期六
		}
		return (y + y / 4 - y / 100 + y / 400 + (13 * m + 8) / 5 + date) % 7;
	}

	//--- 与日期d相等吗 ---//
	public boolean equalTo(Day d) {
		return year == d.year && month == d.month && date == d.date;
	}

	//--- 返回字符串表示 ---//
	public String toString() {
		String[] wd = {"日", "一", "二", "三", "四", "五", "六"};
		return String.format("%04d年%02d月%02d日(%s)", 
								year, month, date, wd[dayOfWeek()]);
	}
}

1)public类

类的声明中加上了public。根据有无public, 类的访问属性有如下不同:

2)构造函数

木程序重载了从不接收年、月、日的构造函数到接收全部的构造函数在内的共5种构造函数。
与方法一样, 构造函数也可以重载,提供了多个构造函数后,对于类的使用者来说、构建类实例的选择范围就比较广了。

各个构造函数的初始化如下所示, 不接收参数的项设为1:

所有的构造函数内部都调用了方法set,同一个类中的方法可以使用“方法名(...) " 的形式进行调用;通过重载构造函数, 我们就可以解决前面提到的问题1和问题2。

问题1
将日期设置为1年1月l日的构造函数不接收参数, 因此、之前的类Day中会发生错误的如下代码就可以正常运行了

for (int i = 0; i < a.length; i++)
a [i] = new Day () ;
for (inti = 0; i < a.length; i++)
a[i].set(2017, 10, 15);

由于可以先创建实例` 然后再设置值, 因此可以很灵活地创建数组。

问题2
构造函数的参数d的类型为Day,通过复制接收到的日期d的字段d.year、d.month、d.date的值, 来初始化日期;这个构造函数的动作如图, dayl的字段值会被复制到对应的day2的各个字段中。

 

问题3  equalTo…判断是否相等的方法

equal To 方法用于判断日期是否相等,将自身的日期和参数d中接收的日期进行比较。如果年、月、日都相等, 则返回true, 否则返回false。与比较引用目标的相等运算符==不同, equal To方法比较的是所有字段的值是否相等。

问题4 toString… 返回字符串表示的方法

to String方法用来返回日期的字符串表示,返回的字符串中,年的部分是4位,月和日的部分是2位. 形式为"2010年05月04 (五),创建字符串时使用的是String.format方法,可以将其理解成一种将System.out.printf在画面上的输出转换为字符串的方法。

class DayTester {

	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);

		System.out.println("请输入day1。");
		System.out.print("年:");  int y = stdIn.nextInt();
		System.out.print("月:");  int m = stdIn.nextInt();
		System.out.print("日:");  int d = stdIn.nextInt();

		Day day1 = new Day(y, m, d);	// 读入日期
		System.out.println("day1 = " + day1);

		Day day2 = new Day(day1);		// 与day1相同的日期
		System.out.println("创建了与day1的日期相同的day2。");
		System.out.println("day2 = " + day2);

		if (day1.equalTo(day2))
			System.out.println("day1和day2相等。");
		else
			System.out.println("day1和day2不相等。");

		Day d1 = new Day();					//    1年 1月 1日
		Day d2 = new Day(2010);				// 2010年 1月 1日
		Day d3 = new Day(2010, 10);			// 2010年10月 1日
		Day d4 = new Day(2010, 10, 15);		// 2010年10月15日

		System.out.println("d1   = " + d1);
		System.out.println("d2   = " + d2);
		System.out.println("d3   = " + d3);
		System.out.println("d4   = " + d4);

		Day[] a = new Day[3];			// 元素个数为3的Day类型数组
		for (int i = 0; i < a.length; i++)
			a[i] = new Day();			// 将全部元素都设置为1年1月1日

		for (int i = 0; i < a.length; i++)
			System.out.println("a[" + i + "] = " + a[i]);
	}
}

输出:

改进终版:

public class Day {
	private int	year	= 1;	// 年
	private int	month = 1;		// 月
	private int	date 	= 1;	// 日

	//-- 构造函数 --//
	public Day()                              { }
	public Day(int year)                      { this.year = year; }
	public Day(int year, int month)           { this(year); this.month = month; }
	public Day(int year, int month, int date) { this(year, month); this.date = date; }
	public Day(Day d)                         { this(d.year, d.month, d.date); }

	//--- 获取年、月、日 ---//
	public int getYear()  { return year; }	// 获取年
	public int getMonth() { return month; }	// 获取月
	public int getDate()  { return date; }	// 获取日

	//--- 设置年、月、日 ---//
	public void setYear(int year)   { this.year  = year; }	// 设置年
	public void setMonth(int month) { this.month = month; }	// 设置月
	public void setDate(int date)   { this.date  = date; }	// 设置日

	public void set(int year, int month, int date) {		// 设置年月日
		this.year  = year;			// 年	
		this.month = month;			// 月
		this.date  = date;			// 日
	}

	//--- 计算星期 ---//
	public int dayOfWeek() {
		int y = year;				// 0 … 星期日
		int m = month;				// 1 … 星期一
		if (m == 1 || m == 2) {		//  :
			y--;					// 5 … 星期五
			m += 12;				// 6 … 星期六
		}
		return (y + y / 4 - y / 100 + y / 400 + (13 * m + 8) / 5 + date) % 7;
	}

	//--- 与日期d相等吗 ---//
	public boolean equalTo(Day d) {
		return year == d.year && month == d.month && date == d.date;
	}

	//--- 返回字符串表示---//
	public String toString() {
		String[] wd = {"日", "一", "二", "三", "四", "五", "六"};
		return String.format("%04d年%02d月%02d日(%s)", 
								year, month, date, wd[dayOfWeek()]);
	}
}

 

  • 5
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值