初识java - 方法的使用


【目标】

  1. 掌握方法的定义以及使用
  2. 掌握方法传参
  3. 掌握方法重载
  4. 掌握递归

一.方法概念及使用

1.1什么是方法

方法就是一个代码片段. 类似于 C 语言中的 “函数”。方法存在的意义(不要>背, 重在体会):

1). 是能够模块化的组织代码(当代码规模比较复杂的时候).
2). 做到代码被重复使用, 一份代码可以在多个位置使用.
3). 让代码更好理解更简单.
4). 直接调用现有方法开发, 不必重复造轮子.

1.2方法定义

语法格式:
修饰符 返回值类型 方法名称([参数类型 形参 …]){
方法体代码;
[return 返回值];
}
示例:
//两数相加
public static int add(int a, int b) {
  int sum = a + b;
  return sum;
}

【注意事项】
1). 修饰符:现阶段直接使用public static 固定搭配。
2). 返回值类型:如果方法有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void。
3). 方法名字:采用小驼峰命名。
4). 参数列表:如果方法没有参数,()中什么都不写,如果有参数,需指定参数类型,多个参数之间使用逗号隔开。
5). 方法体:方法内部要执行的语句。
6). 在java当中,方法必须写在类当中。
7). 在java当中,方法不能嵌套定义。
8). 在java当中,没有方法声明一说。

1.3方法调用的执行过程

【方法调用过程】
调用方法—>传递参数—>找到方法地址—>执行被调方法的方法体—>被调方法结束返回—>回到主调方法继续往下执行。

在这里插入图片描述

【注意事项】
1)定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行。
2)一个方法可以被多次调用。

【示例】
public static void main(String[] args) {
  int a = 10;
 int b = 20;
  int ret = 0;
  System.out.println("第一次调用前:ret = " + ret);
  ret += add(a,b);
  System.out.println("第一次调用后:ret = " + ret);
  System.out.println("第二次调用前:ret = " + ret);
  ret += add(a,b);
  System.out.println("第二次调用后:ret = " + ret);
}
public static int add(int a, int b) {
  return a + b;
}
运行结果:在这里插入图片描述

1.4形参与实参的关系(重要)

  方法的形参相当于数学函数中的自变量,比如:1 + 2 + 3 + … + n的公式为:
在这里插入图片描述
  Java中方法的形参就相当于sum函数中的自变量n,用来接收sum函数在调用时传递的值的。形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。

【示例】
int a = 10;
int b = 20;
add(a,b);    //a,b为实参,在调用时传给形参m,n。
add(10,20);  //10,20为实参,在调用时传给形参m,n。
public static int add(int m, int n) { //m,n为形参。
  return m + n; //返回m+n的和。
}

【注意事项】
在Java中,实参的值永远都是拷贝到形参中,形参和实参的本质是两个实体,在方法体中改变形参的值是不会影响实参的值的。

【示例】
public static void main(String[] args) {
  int a = 10;
  System.out.println("调用方法前 a = " + a);
  amend(a);
  System.out.println("调用方法后 a = " + a);
}
public static void amend(int a) {
  a = 20;//修改形参a的值。
  System.out.println("在方法体内改变形参值后 a = " + a);
}
运行结果:
在这里插入图片描述
【分析原因】
   实参与形参存储的空间是不同的,在方法调用时,只是将实参a中的值拷贝了一份传递给了形参a,因此对形参a操作不会对实参a产生任何影响。
   当然如果想要改变形参值进而改变实参值也是可以的
【解决办法】: 传引用类型参数 (例如数组来解决这个问题)
public static void main(String[] args) {
    int[] arr = {10, 20};
    swap(arr);
    System.out.println("arr[0] = " + arr[0] + " arr[1] = " + arr[1]);
}
public static void swap(int[] arr) {
    int tmp = arr[0];
    arr[0] = arr[1];
    arr[1] = tmp;
  }
运行结果:
在这里插入图片描述

1.5返回类型

1).需要返回值的方法的返回类型如 int String 数组 集合等。(包括基本数据类型和引用数据类型)
【例如】
public static int add(参数列表){
 方法体
 return 返回值;//返回值的数据类型一定与方法的返回类型一致
}
2).不需要返回值的方法的返回类型是 void(void也叫空数据类型)
【例如】
public static void add(参数列表){
 方法体
 //不用写返回值 或者写 return ;
}

二.方法重载

2.1 为什么需要方法重载

   解决在同一个类中,实现相近功能但是由于参数类型,个数不同而导致定义过多方法的问题。方法重载的意义就在于让方法使用相同的方法名,再各自使用自己的形参,最终在用户使用时,系统就可以根据用户输入的数据的类型进行方法的匹配,避免了使用者需要记忆大量的方法名。

2.2方法重载概念

   在自然语言中,经常会出现“一词多义”的现象,比如:“好人
在这里插入图片描述
在自然语言中,一个词语如果有多重含义,那么就说该词语被重载了,具体代表什么含义需要结合具体的场景。
在Java中方法也是可以重载的。
在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。

【示例】
public static void main(String[] args) {
  int num1 = add(10 , 20);//实现两个整数相加
  System.out.println( num1 );
  double num2 = add(10.1 , 20.1);//实现两个浮点数相加
  System.out.println( num2 );
  double num3 = add(10.5 , 20.5 , 30.5);//实现三个浮点数相加
  System.out.println( num3 );
}
public static int add(int a,int b){
  return a + b;
}
public static double add(double a,double b){
  return a + b;
}
public static double add(double a,double b,double c){
  return a + b + c;
}
运行结果:
在这里插入图片描述

【注意事项】
1)方法名必须相同
2)参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
3)与返回值类型是否相同无关
在这里插入图片描述

2.3方法签名(知道就好)

  在同一个作用域中不能定义两个相同名称的标识符。比如:方法中不能定义两个名字一样的变量,那为什么类中就可以定义方法名相同的方法呢?
方法签名即:经过编译器编译修改过之后方法最终的名字。具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。

三.递归

3.1 递归的概念

【递归的过程】
一个方法在执行过程中调用自身, 就称为 “递归”。
递归相当于数学上的 “数学归纳法”, 有一个起始条件, 然后有一个递推公式。
例如, 我们求 N!
起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件。
递归公式: 求 N! , 直接不好求, 可以把问题转换成 N! => N * (N-1)!
【递归的必要条件】
1). 将原问题划分成其子问题,注意:子问题必须要与原问题的解法相同
2). 递归出口
【代码示例】递归求 N 的阶乘

public static void main(String[] args) {
   int recursive = recursive(5);
   System.out.println(recursive);
}
public static int recursive(int n){
  //求n的阶乘
   if(n == 1){
     return 1;//递归出口
   }
   int sum = n * recursive(n - 1);
   return sum;
}
运行结果:
在这里插入图片描述

3.2递归执行的过程分析

过程如:(3.1【代码示例】)
一层一层调用,在一层一层回调和一般函数调用没有什么区别。
【图解】
![在这里插入图片描述](https://img-blog.csdnimg.cn/ce735430a2604eeca59b6da5b773339a.png

关于 “调用栈”
方法调用的时候, 会有一个 “栈” 这样的内存空间描述当前的调用关系. 称为调用栈。
每一次的方法调用就称为一个 “栈帧”, 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息。
后面我们借助 IDEA 很容易看到调用栈的内容。

3.3递归优缺点

递归的优点:代码简洁,可读性高。
递归的缺点:一般情况下空间复杂度较高,运行效率降低。

3.4递归总结

1)、当函数自己调用自己时,系统将自动把函数中当前的变量和形参暂时保留起来,在新一轮的调用过程中,系统为新调用的函数所用到的变量和形参开辟另外的存 储单元(内存空间)。每次调用函数所使用的变量在不同的内存空间。
2)、递归调用的层次越多,同名变量的占用的存储单元也就越多。一定要记住,每次函数的调用,系统都会为该函数的变量开辟新的内存空间。
3)、当本次调用的函数运行结束时,系统将释放本次调用时所占用的内存空间。程序的流程返回到上一层的调用点,同时取得当初进入该层时,函数中的变量和形参 所占用的内存空间的数据。
4)、所有递归问题都可以用非递归的方法来解决,但对于一些比较复杂的递归问题用非递归的方法往往使程序变得十分复杂难以读懂,而函数的递归调用在解决这类 问题时能使程序简洁明了有较好的可读性;但由于递归调用过程中,系统要为每一层调用中的变量开辟内存空间、要记住每一层调用后的返回点、要增加许多额外的 开销,因此函数的递归调用通常会降低程序的运行效率。

3.5递归小练习

  • 1.求斐波那锲数列第N项
 public static void main(String[] args){
	Scanner sc = new Scanner(System.in);
	System.out.println("输入求取数列的第N项:");
	int N = sc.nextInt();
	System.out.println(fibN(N));
}
 public static int fibN(int N){
        //递归出口
        if(N == 1 || N == 2){
            return 1;
        }
        return fibN(N - 1) + fibN(N - 2);
    }
 -----------
 输入:10
 输出:55
  • 2.求斐波那契数列的前 N 项和
 public static void main(String[] args){
	Scanner sc = new Scanner(System.in);
	System.out.println("输入求取数列的前N项:");
	int N = sc.nextInt();
	System.out.println(fibSumN(N));
}
public static int fibSumN(int N){
        if(N<=0){
            return -1;
        }
        int sum = 0;
        for(int i = N; i > 0;i--){
            sum = sum + fibN(i);
        }
        return sum;
    }
    //递归求斐波那契数列的第 N 项1
    public static int fibN(int N){
        //递归出口
        if(N == 1 || N == 2){
            return 1;
        }
        return fibN(N - 1) + fibN(N - 2);
    }
 ---------
 输入:10
 输出:143
  • 3.递归求解汉诺塔问题
public static void main(String[] args) {
        hanoi(1,'A','B','C');
        System.out.println();
        hanoi(2,'A','B','C');
        System.out.println();
        hanoi(3,'A','B','C');
    }
//设三个柱子pos1 pos2 pos3 pos1通过pos2移动到pos3
    public static void hanoi(int number,char pos1,char pos2,char pos3){
        if(number == 1){
            move(pos1,pos3);
        }else{
            hanoi(number - 1,pos1,pos3,pos2);
            move(pos1,pos3);
            hanoi(number - 1,pos2,pos1,pos3);
        }
    }
    //将pose1 -> pose2
    public static void move(char pos1,char pos2){
        System.out.print(pos1 + "->" + pos2 + " ");
    }
---------------------
输出:
A->C 
A->B A->C B->C 
A->C A->B C->B A->C B->A B->C A->C 
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值