11、Java基础---类方法

类方法

一、类方法

向日期类中添加判断"闰年” 的方法,即如下所示的两种方法:

1)判断任意年份:判断任意年份(如2017年)是否是闰年;

2)判断任意日期:判断日期类的实例年份(例如,设置为2017年1O月15日的日期的年份2017年)是否是闰年;

方法1不是针对特定实例设置的,它不属于特定的实例,这一点与类变量(静态字段)相同, 适合用来实现这种处理的就是被称为类方法的静态方法;与特定的实例无关,而是与类整体相关的处理,或者与属于类的各个实例的状态无关的处理,可以实现为静态方法。

创建这两个方法,1为类方法,2为实例方法;假定这两个方法的名称都为isLeap,执行重载;之所以能对这两个方法执行重载是因为存在如下规则:

重载是定义签名不同但名称相同的方法,可以对类方法和实例方法执行重载。

1、判断任意年份(类方法,即静态方法)

静态方法版的isLeap用于判断某一年是否是闰年;由于不是对日期类的实例进行调用,因此可以将其理解为接收int型的“普通方法”,这样的方法可以加上static实现为类方法,类方法版的isLeap的定义如下所示:

//类方法--y年是闰年吗?
public static boolean isLeap(int y) {
	return y%4 == 0 && y%100 != 0 || y % 400 = 0;
}

它会判断形参中接收到的y年是否是闰年

2、判断任意日期(实例方法)

非静态方法,即实例方法版的isLeap 用于判断类实例的日期的年份是否是闰年;判断的对象是方法所属的实例字段year,该方法无需接收参数,其定义如下所示:

//实例方法--自身的日期是闰年吗?
public static isLeap(int y) {
	return y % 4 == 0 && y%100 != 0 || y % 400 == 0;
}

【这里的year就是实例万法isLeap所属的实例中的字段year】

这里执行的判断本质上和类方法版是一样的,程序中充满相同的代码、不利于维护。使用类方法的程序如下所示:

//实例方法--自身的日期是闰年吗?
public boolean isLeap() {
	return isLeap(year);
}

程序将判断year年是否是闰年的操作委托给了类方法版的isLeap。

在这里,实例方法调用了类方法;但反过来,类方法不可以调用实例方法

日期类Day.java

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

	//-- y年是闰年吗?[类方法(静态方法)] --//
	public static boolean isLeap(int y) {
		return y % 4 == 0 && y % 100 != 0 || y % 400 == 0;
	}

	//-- 构造函数 --//
	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 getDay()   { 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 boolean isLeap() { return isLeap(year); }

	//--- 计算星期 ---//
	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()]);
	}
}

测试代码:DayTester.java

import java.util.Scanner;
class DayTester {
	public static void main(String[] args) {
		Scanner stdIn = new Scanner(System.in);
		int y, m, d;
		System.out.print("公历年份:");
		y = stdIn.nextInt();
		System.out.println("该年" + 
							(Day.isLeap(y) ? "是闰年。" : "不是闰年。"));
		System.out.println("请输入日期。");
		System.out.print("年:");  y = stdIn.nextInt();
		System.out.print("月:");  m = stdIn.nextInt();
		System.out.print("日:");  d = stdIn.nextInt();
		Day a = new Day(y, m, d);	// 读入的日期
		System.out.println(a.getYear() + "年" + 
							(a.isLeap() ? "是闰年。" : "不是闰年。"));
	}
}

输出:

1)类方法(静态方法)的调用

System.out.println("该年" + (Day.isLeap(y) ? "是闰年。" : "不是闰年。"));

上述程序调用了判断y年是否是闰年的类方法版isLeap,类方法并不是针对特定实例启动的,因此其调用形式如下:
类名 .方法名()

2)实例方法的调用

System.out.println(a.getYear() + "年" + (a.isLeap() ? "是闰年。" : "不是闰年。"));

此处调用了判断日期a是否是闰年的实例方法版isLeap,实例方法的调用形式如下:

类类型变量名 .方法名()

二、类变量和类方法

根据是静态的还是非静态的,字段和方法互相访问的情况有所不同。例如,日期类的类方法isLeap无法访问实例变量year、month、date。这是因为无法确定访问哪一个实例的year、month、date (甚至有可能不创建任何实例)

通过代码来验证一下方法和字段的访问属性:Static.java

class Static {
	private static int s;		// ■静态字段(类变量)
	private int a;				// □非静态字段(实例变量)
	public static void m1() { }	// ●静态方法①(类方法)
	public        void f1() { }	// ○非静态方法①(实例方法)
	//-- ●静态方法②(类方法) --//
	public static void m2(int x) {
		s = x;		// ■可以访问静态字段
//	   a = x;		// □不可以访问非静态字段(错误)
		m1();		// ●可以调用静态方法
//	   f1();		// ○不可以调用非静态方法(错误)
	}
	//-- ○非静态方法②(实例方法) --//
	public void f2(int x) {
		s = x;		// ■可以访问静态字段
		a = x;		// □可以访问非静态字段
		m1();		// ●可以调用静态方法
		f1();		// ○可以调用非静态方法
		System.out.println("s = " + s + "  a = " + a);
	}
}
public class StaticTester {
	public static void main(String[] args) {
		Static c1 = new Static();
		Static c2 = new Static();
		Static.m2(5);
		c1.f2(10);
		c2.f2(20);
	}
}

输出:

在类Static中,分别存在静态字段和非静态字段各一个、静态方法和非静态方法各两个。【注释掉的地方的访问会发生错误(不注释掉会发生编译错误)】
各个字段和方法的关系如图所示非静态字段(变量)和非静态方法(实例方法)属于实例cl和c2而静态字段(实类量)和静态方法(类方法)是独立于实例的,只有一个。

1)实例方法(非静态方法)

可以访问所有的非静态字段、静态字段、非静态方法、静态方法(例如,方法f2可以访问所有的非静态字段a、静态字段s 、非静态方法fl、静态方法m1),实例方法既可以访问“自身持有的变量/方法” ,也可以访问“大家共享的变量/方法” 。

2)类方法(静态方法)

可以访问静态字段和静态方法,但不可以访问非静态字段和非静态方法;
这是因为访问字段a和方法fl时,无法判断a和fl是属于cl还是属于c2;
类方法不具有“自身持有的变量/方法” ,只可以访问“大家共享的变量/方法” 。

计算三个整数值中最大值的程序:

// 计算3个整数值中的最大值(方法版)

import java.util.Scanner;

class Max3Method {

	//--- 返回a, b, c中的最大值 ---//
	static int max(int a, int b, int c) {
		int max = a;
		if (b > max) max = b;
		if (c > max) max = c;
		return max;
	}

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

		System.out.print("整数a:");  int a = stdIn.nextInt();
		System.out.print("整数b:");  int b = stdIn.nextInt();
		System.out.print("整数c:");  int c = stdIn.nextInt();

		System.out.println("最大值是" + max(a, b, c) + "。");
	}
}

输出:

1)max 必须为类方法的原因

声明中加上static的main方法是类方法(静态方法),由于类方法无法调用同一个类中的实例方法,因此max也必须加上static,声明为类方法。如果max声明为不加static的实例方法(非静态方法),那么main方法就无法进行调用了(会发生编译错误)。

2)main方法中使用max(...)进行调用的原因

类方法的调用形式为"类名.方法名(...) " ,但main方法只使用了”方法名(...) " 进行调用,像这祥省略类名,只使用方法名进行调用的原因非常简单,因为main方法和max属于同—个类。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值