1. 方法概述和格式说明
- 什么是方法
方法就是完成特定功能的代码块
在很多语言中都有函数的定义,但是在JAVA语言中,我们将其称之为方法。 - 方法的格式
修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2 ....){
方法体;
return 返回值;
}
- 方法的格式详细说明
(1): 修饰符 比较多,后面会详细介绍。目前使用 public static (2): 返回值类型 用于限定返回值的数据类型
(3): 方法名 就是一个名称,它的存在是为了方便我们调用方法
(4): 参数类型 限定调用方法时传入参数的数据类型
(5): 参数名 是一个变量,接收调用方法时传入的参数这个参数其实有一个专业的名词,被称之为形式参数,它的作用是用来接收实际参数的.
(6): 方法体 完成功能的代码
(7): return 结束方法以及返回方法指定类型的值
(8): 返回值 就是功能的结果,由return带回,带回给调用者
2. 方法之求和案例及其调用
- 需求:求两个数据之和的案例
- 如何写一个方法
两个明确
(1):返回值类型 明确功能结果的数据类型
(2):参数列表 你要传递几个参数,以及每一个参数的数据类型 - 方法调用(有明确返回值的调用)
a:单独调用,一般来说没有意义,所以不推荐。
b:赋值调用,推荐方案。
c:输出调用,但是不够好。因为我们可能需要针对结果进行进一步的操作。
案例:
import java.util.Scanner;
public class Demo {
public static void main(String[] args) {
System.out.println("请输入第一个数");
Scanner sc = new Scanner(System.in);
int i = sc.nextInt();
System.out.println("请输入第二个数");
Scanner sc2 = new Scanner(System.in);
int j = sc2.nextInt();
int sum=function(i,j);//调用了名为function的方法
System.out.println("这两个数之和是 "+sum);
}
private static int function(int a,int b) {
//定义了一个名为function的方法来接受参数并执行两个数相加的方法
int sum =0;
sum=a+b;
return sum;//因为是又返回值类型的,因此将两数之和返回去
}
}
3. 方法的注意事项
A: 方法不调用不执行
B: 方法与方法是平级关系,不能嵌套定义
C: 方法定义的时候参数之间用逗号隔开
D: 方法调用的时候不用在传递数据类型
E: 如果方法有明确的返回值,一定要由return带回一个对应的值
public class MethodTest08{
//主方法,入口
public static void main(String[] args){
//int a = 100;
// 这个赋值原理是:将a变量中保存的100这个数字复制一份传给b变量。
// 所以a和b是两个不同的内存空间,是两个局部变量。
//int b = a;
System.out.println("main begin");
int x = 100;
m1(x);
System.out.println("main over");
}
public static void m1(int i){ // i是局部变量
System.out.println("m1 begin");
m2(i);
System.out.println("m1 over");
}
public static void m2(int i){
System.out.println("m2 begin");
m3(i);
System.out.println("m2 over");
}
public static void m3(int i){
System.out.println("m3 begin");
System.out.println(i);
System.out.println("m3 over");
}
}
程序内存图
4. Java语言基础(方法的练习)(掌握)
A:案例演示: 需求:根据键盘录入的数据输出对应的乘法表
案例:
//根据键盘录入的数据输出对应的乘法表
import java.util.Scanner;
public class Demo2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入乘法表的阶数");
int i = sc.nextInt();
function(i);
}
private static void function(int a) {
for (int i = 1; i <=a; i++) {
for (int j = 1; j <=i ; j++) {
System.out.print(j+"*"+i+"="+(j*i)+"\t");
}
System.out.println();
}
}
}
5. 方法重载概述
方法的重载
在同一个类中可以定义多个同名方法,但要求每个同名方法之间,参数的个数,返回值的类型要求不同
public static void main(String[] args) {
int x1 = 10;
int x2 = 20;
int retValue1 = sumInt(x1 , x2);
System.out.println(x1 + "+" + x2 + "=" + retValue1);
long y1 = 10L;
long y2 = 20L;
long retValue2 = sumLong(y1 , y2);
System.out.println(y1 + "+" + y2 + "=" + retValue2);
double z1 = 10.0;
double z2 = 20.0;
double retValue3 = sumDouble(z1, z2);
System.out.println(z1 + "+" + z2 + "=" + retValue3);
}
public static int sumInt(int a , int b){
return a + b;
}
public static long sumLong(long a , long b){
return a + b;
}
public static double sumDouble(double a , double b){
return a + b;
}
运行结果
以上三个方法功能“相似”,都是求和,只不过参与求和的数据类型不同,因此定义了三个方法,分别起了三个不同的方法名。这种方式会增加程序员编程的压力,因为程序员起码要记忆三个方法名,另外代码也不是很美观。怎么解决呢?我们来看看使用方法重载机制之后会是怎样,请看以下代码以及运行结果:
public static void main(String[] args) {
int x1 = 10;
int x2 = 20;
int retValue1 = sum(x1 , x2);
System.out.println(x1 + "+" + x2 + "=" + retValue1);
long y1 = 10L;
long y2 = 20L;
long retValue2 = sum(y1 , y2);
System.out.println(y1 + "+" + y2 + "=" + retValue2);
double z1 = 10.0;
double z2 = 20.0;
double retValue3 = sum(z1, z2);
System.out.println(z1 + "+" + z2 + "=" + retValue3);
}
public static int sum(int a , int b){
return a + b;
}
public static long sum(long a , long b){
return a + b;
}
public static double sum(double a , double b){
return a + b;
}
以上代码使用了方法重载机制,三个“功能相似”的方法名字都叫做 sum,只不过方法的形参不同,这样对于程序员来说,调用方法时所需要记忆的方法名更少,代码更加美观
满足以下三个条件:
① 在同一个类当中。
② 方法名相同。
③ 参数列表不同:个数不同算不同, 顺序不同算不同,类型不同也算不同。
6. 递归
先看一段代码:
public class RecursionTest01 {
public static void main(String[] args) {
m();
}
public static void m(){
System.out.println("m begin");
m();
System.out.println("m over");
}
}
以上代码的执行结果如下图所示:
以上代码的执行过程中,一直输出“m begin”,“m over”一次也没有输出,直到最终发生了错误: java.lang.StackOverflowError,这个错误是栈内存溢出错误,错误发生后,JVM 退出了,程序结束了
综上所述,递归其实就是方法在执行的过程中调用了另一个方法,而另一个方法则是自己本身。在代码角度来看就是在 a()方法中调用 a()方法,使用递归须谨慎,因为递归在使用的时候必须有结束条件,没有结束条件就会导致无终止的压栈,栈内存最终必然会溢出,程序因错误的发生而终止。
递归概述
方法定义中调用方法本身的现象
注意事项
要有出口,否则就是死递归
次数不能太多,否则就内存溢出
生活中的递归
小时候爷爷经常讲的故事:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚给小和尚讲故事,讲的是什么,讲的是,从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚给小和尚讲故事,讲的是什么,讲的是。。。。。
当然这就成了一个死循环了。。。
递归的思想
递归就是把一个大问题分解成几个小问题,小问题再分解,最后解决了小问题,大问题也就迎刃而解了。
下面我们来看递归做出5!
public static void main(String[] args) {
//用递归的思想来处理5的阶乘
int r = factorial(5);
System.out.println("结果" + r);
}
private static int factorial(int n) {
if (n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
请看这段代码的内存图:
那么,一个递归程序有合法有效的结束条件就一定不会发生栈内存溢出错误吗?在实际开发中遇到这个错误应该怎么办?
一个递归程序有的时候存在合法有效的终止条件,但由于递归的太深,在还没有等到条件成立的时候,栈内存已经发生了溢出,这种情况也是存在的,所以实际开发中我们尽可能使用循环来代替递归算法,原则是:能不用递归尽量不用,能用循环代替的尽可能使用循环。当然,如果在开发中遇到了由于使用递归导致栈内存溢出错误的发生,首先,我们要检查递归的终止条件是否合法,如果是合法的还是发生栈内存溢出错误,那么我们可以尝试调整堆栈空间的大小。怎么调整堆栈大小呢,大家可以研究一下下图中的一些参数,这里就不再讲解内存大小的调整了,这不是初级程序员应该掌握的。