一、定义
所谓方法,就是用来解决一类问题的代码的有序组合,是一个功能模块。举个例子,比如说我想输出“张三-职业1”和“李四-职业2”这两条数据,我们可以怎么做呢?最简单的就是:
public static void main(String[] args) {
System.out.println("张三-职业1");
System.out.println("李四-职业2");
}
但是这种写法会带来大量的重复且不利于日后维护的代码。因此,方法应运而生。对上面同样的问题,我们可以用方法来写:
public static void main(String[] args) {
Test1 sTest1 = new Test1();
sTest1.show("张三", "职业1");
sTest1.show("李四", "职业2");
}
public void show(String name, String occ) {
System.out.println(name + "-" + occ);
}
和前一种写法相比,第二种写法最明显的就是提供了一种模板,只需要调整输入的参数,就可以得到想要的结果,这其实也就是所谓的模块化。将需要实现的功能变成一个个模块,需要什么功能,就调用什么模块,降低代码的耦合度,也利于日后代码的维护。
二、分类
根据方法是否带参数,是否有返回值可以分为四类:
-
无参无返回值方法
修饰符 void 方法名(){ // 实现功能 }
-
无参带返回值方法
修饰符 类型 方法名(){ // 实现功能 return 类型; }
-
带参无返回值方法
修饰符 void 方法(数据类型 变量名, ……){ // 实现功能 }
-
带参带返回值方法
修饰符 类型 方法(数据类型 变量名, ……){ // 实现功能 return 类型; }
三、参数传值
参数可以简单看做两类:形式参数和传递参数(实际参数)。二者的区别就在于形参是虚的,没有实际值,只是定义了它的存在,而传参则是实的,具有确定值,可以被使用。
再简单点说就是,方法定义的那个括号中所写的就是形参,只是一个代指的符号,而调用方法时所传递的那个数值就是传参,真正参与运算。
参数所接受的传值类型就是整个数据类型,换而言之就是包括了基本数据类型和引用数据类型。
- 如果传递的参数是基本数据类型,那么传递进方法的参数值不会改变方法外原参数的值。
- 如果传递的参数是引用数据类型,那么传递进方法的参数值会改变方法外原参数的值。
什么意思呢?我们可以看下面的一个示例。
public static void main(String[] args) {
// 数组定义
int name = 1;
int[] num = {1, 1, 1};
Test1 sTest1 = new Test1();
sTest1.show(name, num);
System.out.println();
System.out.println("运行方法后:");
sTest1.show(name, num);
}
public void show(int name, int[] num) {
System.out.println("name:" + name);
System.out.print("num:");
for (int i:num) {
System.out.print(i + " ");
}
// 对参数进行修改
name = 2;
num[0] = 0;
}
/* 输出结果:
name:1
num:1 1 1
运行方法修改参数后:
name:1
num:0 1 1
*/
示例中的方法有两个参数,一个是int类型(基本数据类型),另一个是数组类型(引用数据类型)。我们可以用一张表来说明:
name(基本数据类型) | num(引用数据类型) | |
---|---|---|
第一次进入方法 | name = 1 | [1, 1, 1] |
第二次进入方法 | name = 1 | [0, 1, 1] |
第一次进入方法时,两个参数的值和初始化时的值一样,没有发生改变。但当第二次进入方法后,我们会发现,基本数据类型的值name还是和原来的一样,没有发生改变,但引用数据类型的值num却发生了改变,其索引0的值从1变成了0。
为什么同样对参数的值进行了修改,结果却不同呢。关于这一点,身为菜鸟的我也不是很清楚,查了查后发现了值传递和引用传递,这一点据我猜测,应该和基本数据类型和引用数据类型的定义有关。
那么值传递和引用传递到底有什么区别呢?简单点来说是,复制体和本体的区别。值传递,所传递的就是本体的复制体,既然是复制体,那么对它所进行的一系列操作势必影响不到本体。而引用传递,其所传递的就是本体的引用,既然是引用,那么对其所进行的一系列操作也就势必会回馈至本体身上。
PS.字符串定义变量String str = “test”;用的也是值传递的方式。
四、可变参数
public static void main(String[] args) {
Test2 sTest2 = new Test2();
System.out.println(sTest2.sum(1)); // result = 1
System.out.println(sTest2.sum(1,2)); // result = 3
System.out.println(sTest2.sum(1,2,3)); // result = 6
}
public int sum(int... num) {
int result = 0;
for (int i:num) {
result += i;
}
return result;
}
如案例所示,调用同一个方法,所传递的参数个数不同,但竟然没有编译错误,反而输出了正确的结果,这是为什么?其实,这就是可变参数了。
代码中的那…就是用来表示可变参数的定义。
可变参数我们把它看成一个长度未知的数组。不同的是,我们不能把它和数组真正的划上等号。我们可以把数组当作实参传递给可变参数,但却不能把可变参数当作实参传递给数组。
在可变参数的定义上,我们要注意:
- 可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数。
- 由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数。
五、函数与方法的不同
事实上,我在学习的时候曾经遇上过这么一个问题:函数与方法有什么不同?看到问题的时候,我就懵了,想了想,查了些资料后,我发现,其实这两者可以说不同,也可以说没什么不同。
在绝大多数的时候,我们默认函数=方法。但要细究起来,二者应该说还是不同的。
函数一词,大多出现在像C语言这种面向过程的编程语言中,而方法一词则出现在面向对象的编程语言中,比如Java。面向过程和面向对象之间的区别,肯定是不同,而它们之间的不同点也不用我多说。但是根据它们的不同点,我们可以推导出两个函数与方法的名称应用法则:
- 在使用面向过程的编程语言中,不称方法,而称函数,反之亦然。
- 在使用非对象方法时,不称方法,称函数,反之亦然。
关于第二点,那是因为有些地方我们的编程没有涉及到对象方法的调用,究其本质也就是同面向过程一般,属于函数的调用。不过说实话,纠结这个的叫法也没有多大的意义,随自己的喜欢就行。