成员方法

一. 方法的概述

类中的成员方法分为两种:静态成员方法和非静态成员方法。因此方法是类或对象的行为特征的抽象,从功能上看,方法类似于传统结构化程序设计里的函数,只不过Java里的方法不能独立存在,所有的方法必须定义在类中。方法在逻辑上要么属于类,要么属于对象。

二. 方法的所属性

static修饰的方法属于类,否则属于对象。

三. 方法的调用

因为Java中的方法不能独立存在,它必须属于一个类或对象,因此方法也不能像函数一样独立独立运行,执行方法必须使用类或对象作为调用者,既所有的方法都必须使用“类.方法”或“对象.方法”的形式调用。
那么产生一个问题:同一个类中的方法相互如何调用?

  1. 同一个类中的类方法的调用:默认使用类来调用
  2. 同一个类中的对象方法调:默认使用this调用。
    注意:
    不能在类方法中调用对象方法。后面会在static关键词中来解释这个问题。

四. 方法参数的值传递

  1. 什么是参数?
    我们知道方法的调用必须使用类或对象来作为主调者。如果声明方法时定义了形参声明,则调用时必须给这些形参指定参数值,调用方法时传递给新参的参数值被称为实参。
public class Person{
	public void study(String name){  //这里声明的String name 为形参
		System.out.println(name,"人类会学习")
	}
	public static void main(String [] args){
		Person p = new Person();
		p.study("凝练于心") //  这里“凝练于心”就是实际参数
	}
}
  1. 参数的传递机制
    首先说明,Java方法里的参数传递机制只有一种值传递所谓值传递,就是将实际参数值的副本(复制品)传入方法内,参数本身不会受到任何影响。
  • 参数为基础数据类型的值传递

我们看以下代码,方法的参数为基础数据类型。

public class PrimitiveTransferTest{
	public static void swap(int a ,int b){
		int tmp = a;
		a = b;
		b = tmp;
		System.out.println("swap方法里,a的值是:"+ a +", b的值是:" + b);
	}
	public static void main(String[] args){
		int a = 6;
		int b = 9;
		swap(a,b);
		System.out.println("交换后,a的值是:"+ a + ";b的值是:" + b)
	}
}

运行结果为:

swap方法里,a的值是:9;b的值是6
交换后,a的值是:6;b的值是9

从运行结果来看,main()方法中的变量a,b,并不是swap()方法里的a,b。其实swap()方法的a和b只是main()方法里变量a,b的复制品。其实在整个运行过程中产生了四个变量,两a两b。只不过其中一对a,b存储在main()方法栈区中,另一对a,b存储在swap()方法栈区中。

  • 参数为引用数据类型的值传递

我们看以下代码,方法的参数为引用数据类型。

class Datawrap{
	int a;
	int b;
}
public class RerenceTransferTest{
	public static void swap(Datawrap dw){
		int tmp = dw.a;
		dw.a =dw.b;
		dw.b = tmp;
		System.out.println("swap 方法里,a成员变量的值是:" + dw.a + 
						";b 成员变量的值是:" + dw.b );
	}
	public static void main(String[] args){
		Datawrap dw = new Datawrap();
		dw.a = 6;
		dw.b = 9;
		swap(dw);
		System.out.println("交换结束后,a成员变量的值是:" + dw.a + 
							";b 成员变量的值是:" + dw.b );
	}
}

执行后,看到如下结果

swap方法里,a成员变量的值是:9;b 成员变量的值是:6
交换结束后,a成员变量的值是:9;b 成员变量的值是:6

分析:
从运行结果上看,swap()方法交换a,b成功,并且main()方法里的a,b也被交换了。**这容易产生一个错觉:调用swap方法时,传入swap方法内的就是dw对象本身,而不是它的复制品。但这只是一个错觉!**我们来分析以下:首先我们知道对象是存储在堆中的,而方法和引用变量是存储在栈区的。那么dw对象(new Datawrap())是存储在堆内存中,而dw变量本身存储在栈中,它的值为对象的内存地址。因此当我们把dw变量作为参数传递时,传递的是对象内存地址的复制品,因此在swap方法中由于dw也是指向对象的。因此在swap修改a,b之后,堆内存中的对象也发生了改变。

3. 总结:方法参数的传递机制始终是: 值传递

五、可变参

从JDK 1.5 之后,Java允许定义形参个数可变的参数,从而允许方法指定数量不确定的形参。

  1. 可变参定义
    在定义方法时:在最后一个形参的类型后面增加三点(…),则表明该形参可以接受多个参数值,并且多个参数值被当成**数组**传入。
方法(参数1,可变参类型... 参数名)

此外还可以这样定义:

方法(参数1,可变参数类型[] 参数明) //以数组形式定义可变参,数组形参

看如下代码:

public class Varargs{
	//定义形参个数可变的方法
	public static void test0(int a ,String...books){
	//books 当成数组来处理
		for (String tmp : books){
			System.out.println(tmp);
			}
		System.out.println(a);
	}
	public static void test1(int a ,String[] books){
	//处理books数组
		for (String tmp : books){
			System.out.println(tmp);
			}
		System.out.println(a);
	}
	public static void main(String[] args){
	//测试test0方法和test1
		test0(5,"凝练于心","学Java"); //调用时test0参数不需用数组传递
		test1(1,new String[]{"Java爱好者","学Java","学数据结构"})//调用时必须用数组
	}
}

总结

  • 可变参的传入会以数组的形式传递入内;
  • 以三点(…)形式的可变参定义方法时,调用该方法不需要以数组的形式传入,但是程序会自动的将传入的参数隐式存储在数组中;
  • 以数组形式的可变参定义方法时,调用该方法是必须以数组的形式传入参数。
    注意
    · 以三点(…)形式定义可变参时,该可变参只能处于形参列表的最后,因此一个方法内最多只能包含一个长度可变的形参;此外长度可变的形参本质上就是一个数组类型的形参从而调用包含一个长度可变形参的方法时,这个长度可变的形参即可传入多个参数,也可以传入一个数组
    · 以数组形式定义可变参时,该可变参可以处于形参列表的任意位置,因此一个方法内可以包含多个数组形式的可变参。但是,调用包含数组形式的可变参的方法时,只能传入数组来调用。

六、方法重载

Java中允许同一个类中定义多个同名方法,只要形参列表不同就行。Java程序中确定一个方法需要三个元素:调用者(方法的所属者)、方法名(方法的标志)、形参列表

方法重载: 如果同一个类中包含了两个或两个以上方法的方法名相同,但形参列表 不同,则被称为方法重载

因此:从方法定义来看,方法重载的要求就是两同一不同同一个类、相同的方法名、形参列表不同。至于方法的其它部分,如修饰符、返回值类型等,与方法重载没有任何关系。

注意当一个类中存在方法重载时,这时不推荐利用可变形参来定义方法实现方法重载。