【Java基础】(八)方法(即C等语言中的函数)


方法的概念在之前已经提到过,不在赘述。

一、为什么要有方法

假如我们想要获得一到一百所有数相加的和,和一到五十所有数相加的和,如果不用方法。

	//1+2+3+....+100
	int sum = 0;
	for(int i = 1; i <= 100; i++) {
		sum = sum + i;
	}
	//1+2+3+....+50
	int sum = 0;
	for(int i = 1; i <= 50; i++) {
		sum = sum + i;
	}

很明显,这两段代码其实是基本一样的,就是换一下数字而已。这样的代码重复度就很高,用行话说,就是代码冗余度高。为了解决这一问题,我们就引入了方法的概念。

二、方法定义

[修饰符] 返回值类型 方法名(参数列表) {
	//方法体
	return 返回值;
}

比如,写一个将将两个int类型数相加的方法:

	/*
	 * 定义一个方法,实现两个整数相加---有返回值
	 * */
	public static int add(int a, int b){
		b += a;
		return b;
	}
  1. 修饰符在某些场合下可以没有,当前修饰符为public static;
  2. 返回值类型要和返回值的类型一样;
  3. 方法中可以没有返回值,"return 返回值;"可以写成"return;"或者不写,返回值类型为void;
  4. 方法名要符合标识符的命名规范;
  5. 参数列表: 数据类型 参数名1, 数据类型 参数名2, 数据类型 参数名3,多个参数时以逗号隔开,方法当中可以没有参数列表;
  6. 大括号成对存在;
  7. 方法要定义在类中。

三、方法调用----使用方法

格式(参数与方法的参数列表的顺序、数量对应):

方法名(参数)

在main中调用我们刚写好的方法:

package com.daw.test;

public class Test1 {

	public static void main(String[] args) {
		int a = 5, b = 10;
		System.out.println(add(a, b));
	}
	
	/*
	 * 定义一个方法,实现两个整数相加---有返回值
	 * */
	public static int add(int a, int b){
		b += a;
		return b;
	}
	
}

四、方法重载

满足以下条件,称为方法重载:

1. 在同一个类中;
2. 方法名相同,参数列表不同
3. 和返回值类型没有关系

比如,我们刚完成了一个int形相加的方法,此时我们如果也有double型需要相加该怎么办呢,又或者我们有三个数需要相加该怎么办呢。我们可以重载我们的add方法:

package com.daw.test;

public class Test01 {

	public static void main(String[] args) {
		int a = 5, b = 10;
		double c = 5.0, d =10.0;
		int e = 1, f = 2, g = 3;
		System.out.println(add(a, b));
		System.out.println(add(c, d));
		System.out.println(add(e, f, g));
	}
	
	/*
	 * 定义一个方法,实现两个整数相加---有返回值
	 * */
	public static int add(int a, int b){
		b += a;
		return b;
	}
	
	/*
	 * <重载>
	 * 定义一个方法,实现两个浮点数相加---有返回值
	 * */
	public static double add(double a, double b) {
		return a+b;
	}
	
	/*
	 * <重载>
	 * 定义一个方法,实现三个整数相加---有返回值
	 * */
	public static int add(int a, int b, int c) {
		return a+b+c;
	}
}

在double型重载时,我们的返回值类型变成了double,但这并不影响我们的重载,重载只和参数列表有关,和返回值类型无关。

五、方法递归

当方法调用方法本身时,称为方法递归
如斐波那契数列,即可使用递归来打印。(斐波那契数列:第一项与第二项都为1,此后的每一项都为其前面两项的和。如食堂的粥,就是斐波那契粥,今天的粥等于昨天的粥加前天的粥。):

package com.daw.test;

public class Test01 {

	public static void main(String[] args) {
		System.out.println(f(6));
	}
	/*
	 * 方法递归
	 * 递归函数必须要有明确的结束标志,否则会发生栈溢出错误!
	 * 斐波那契数列 --- 求第n项的值
	 * */
	public static int f(int n) {
		if(n == 1 || n == 2){
			return 1;
		}
		return f(n-1) + f(n-2);
	}

}

尝试编写运行下面的代码:

package com.daw.test1;

public class Test3 {

	public static void main(String[] args) {
		Test();
	}
	
	public static void Test() {
		Test();
	}

}

一瞬间,整个控制台被红色字体填满。
在这里插入图片描述
当你把右侧的侧边滚动条拉倒最上面,你会看到这个错误的解释。
在这里插入图片描述

StackOverflowError:栈溢出,方法递归时,每个方法都会被压入系统的一个栈中。
当你的方法没有退出条件,或者递归次数过多时,都会导致我们系统中的这个栈被塞满,从而导致程序无法再继续运行。
StackOverflow和死循环有点相似,要避免栈溢出,方法就有明确的退出条件。

六、可变参数

1.可变参数必须是参数列表的最后一个参数
2.参数列表中可变参数只能有一个
3.可变参数本质上是一个数组
4.在可变参数中传参,既可以传递多个参数,也可以直接传递一个数组
5.可变参数在方法内部当成数组使用

package com.daw.test;

public class Test02 {

	public static void main(String[] args) {
		System.out.println(add(1, 2, 3, 4, 5));
		int[] arr = {1, 2, 3, 4, 5};
		System.out.println(add(arr));
	}
	
	public static int add(int... args) {	//args即为一个可变参数
		int sum = 0;
		for(int i : args){
			sum += i;
		}
		return sum;
	}
	
}

七、形式参数与实际参数

形式参数:方法定义时,参数列表中的参数
实际参数:方法调用时,实际传递给方法的参数
package com.daw.test;

public class Test03 {

	public static void main(String[] args) {
		int m = 5, n = 6;
		int sum = add(m, n);		//此处的m,n即为实际参数
		System.out.println(sum);
	}
	
	public static int add(int a, int b) {	//a,b为形式参数
		return a+b;
	}

}

其实很多人都容易把形参和实参的概念搞不清楚。其实很简单,你不要把它看成是计算机里的东西。
有一个西红柿炒鸡蛋的菜谱,说需要西红柿,鸡蛋等等这些原材料,但是在菜谱中写的 “西红柿,鸡蛋” 这些字,其实只是一堆名字,他们并不是真的在菜谱上放一些西红柿、鸡蛋,他们只用来给你解释怎么做这道菜的,这就是形式参数。
但是你如果真想做一道西红柿炒鸡蛋,那你就得拿来真正的西红柿,鸡蛋,然后依据菜谱上说的,把那些名字与这些实物对应,然后去做菜。这些实物,就是实际参数。
简而言之,形式参数是假的,是个代号,我可以说是西红柿,也可以说是番茄,还可以说是特麻头。它叫什么无关,你知道它对应的实际的东西是什么那就行,只要能对应上,你说是 “红色的具有防水外壳内含大量液状物质的神秘圆状物”都行。

八、值传递和引用传递

参数列表中是基本数据类型时,其为值传递
值传递:方法体内的操作,对实际参数无任何影响。

package com.daw.test;

public class Test03 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int m = 5, n = 6;
		swap(m, n);
		System.out.println("m = " + m);
		System.out.println("n = " + n);
	}
	
	public static void swap(int a, int b) {
		int temp = a;
		a = b;
		b = temp;
		
		System.out.println("a = " + a);
		System.out.println("b = " + b);
	}
}

输出内容可看出。
swap内部,m对应a,n对应b,互换成功;swap外部,m,n并没有互换。


参数列表中不是基本数据类型时,其为引用传递
引用传递:方法体内的操作,会对实际参数的“值”产生影响

package com.daw.test;

public class Test03 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] x = {3, 2, 1};
		int[] y = {5, 6};
		swap(x, y);
		System.out.println("x[0] = " + x[0]);
		System.out.println("y[0] = " + y[0]);
	}
	
	public static void swap(int[] a, int[] b) {
		int temp = a[0];
		a[0] = b[0];
		b[0] = temp;
		
		System.out.println("a = " + a);
		System.out.println("b = " + b);
	}

}

输出内容可看出。
swap内部,x[0]对应a[0],y[0]对应b[0],互换成功;swap外部,x[0],y[0]也互换了。

这一区别的主要原因是,方法不真的这我们给它提供的这个实际参数直接去用了,而是把我们提供这个参数的值给复制了,又另整了一个新的变量以供方法使用。
但我们前面学习了,引用数据类型的值其实是个地址,你整个新的去用了,但也是改的这个地址上的数据,但地址本身本来就不会变化。所以实际参数也就跟着一起改变了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值