一文让你理解Java中的方法、重载与递归

Java方法

方法是什么?

Java 方法是语句的集合,它们在一起执行一个功能

  • 方法是解决一类问题的步骤的有序组合
  • 方法包含于类或对象中
  • 方法在程序中被创建,在其他地方被引用

方法的优点

  1. 使程序变得更简短而清晰
  2. 有利于程序维护
  3. 可以提高程序开发的效率
  4. 提高了代码的重用性

Java 方法的命名规则

  1. 必须以字母、下划线(_) 或 美元($) 开头
  2. 可以包括数字,但不能以它开头

方法的定义

一般情况下,定义一个方法包含以下语法

修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

方法包含一个方法头和一个方法体

下面是一个方法的所有部分

  • 修饰符: 修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型
  • 返回值类型 : 方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字 void
  • 方法名: 是方法的实际名称。方法名和参数表共同构成方法签名
  • 参数类型: 参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数
  • 方法体: 方法体包含具体的语句,定义该方法的功能

return语句在方法中的作用

  1. 返回方法指定类型的值
  2. 结束方法的执行,终止后边代码的执行
  3. ⼀个⽅法最多只能执⾏⼀条return语句,即使你有多个return
  4. 不可达语句
    1. 在⼀定会被执⾏的return语句后
    2. 在循环中⽆条件的break后写语句,会出现不可达语句
    3. 在死循环(没有break来结束的死循环)后写语句,会出现不可达
      语句

重载(overload)

重载 ( overloading ) 是在一个类里面,方法名字相同,而参数个数不同、顺序不同、类型不同,返回类型可以相同也可以不同

每个重载的方法 ( 或者构造函数 ) 都必须有一个独一无二的参数类型列表

 //以下两个参数类型顺序不同
    public String test(int a,String s){
        System.out.println("test3");
        return "returntest3";
    }   

    public String test(String s,int a){
        System.out.println("test4");
        return "returntest4";
    }   

重载规则

  1. 被重载的方法必须改变参数列表 (参数个数或类型或顺序不一样)
  2. 被重载的方法可以改变返回类型
  3. 被重载的方法可以改变访问修饰符
  4. 被重载的方法可以声明新的或更广的检查异常
  5. 方法能够在同一个类中或者在一个子类中被重载
  6. 无法以返回值类型作为重载函数的区分标准

注意事项

  1. 重载方法参数必须不同
  2. 重载只与方法名与参数类型相关与返回值无关
  3. 重载与具体的变量标识符无关

参数传递

参数传递,可以理解当我们要调用一个方法时,我们会把指定的数值,传递给方法中的参数,这样方法中的参数就拥有了这个指定的值,可以使用该值,在方法中运算了。这种传递方式,我们称为参数传递。

在这里,定义方法时,参数列表中的变量,我们称为形式参数
调用方法时,传入给方法的数值,我们称为实际参数

递归

递归是⼀种常⻅的解决问题的⽅法,即把问题逐渐简单化。 递
归的基本思想就是 ⾃⼰调⽤⾃⼰ ,⼀个使⽤递归技术的⽅法将
会直接或者间接的调⽤⾃⼰。利⽤递归可以⽤简单的程序来解
决⼀些复杂的问题。

递归的定义

递归是⼀种常⻅的解决问题的⽅法,即把问题逐渐简单化。 递
归的基本思想就是 ⾃⼰调⽤⾃⼰ ,⼀个使⽤递归技术的⽅法将
会直接或者间接的调⽤⾃⼰。利⽤递归可以⽤简单的程序来解
决⼀些复杂的问题。⽐如:⼤多数排序使⽤的就是递归算法

递归的三要素

第一要素:明确你这个函数想要干什么

对于递归,我觉得很重要的一个事就是,这个函数的功能是什么,他要完成什么样的一件事,而这个,是完全由你自己来定义的。也就是说,我们先不管函数里面的代码什么,而是要先明白,你这个函数是要用来干什么。

例如,我定义了一个函数

// 算 n 的阶乘(假设n不为0)
int f(int n){
    
}

这个函数的功能是算 n 的阶乘。好了,我们已经定义了一个函数,并且定义了它的功能是什么,接下来我们看第二要素。

第二要素:寻找递归结束条件

所谓递归,就是会在函数内部代码中,调用这个函数本身,所以,我们必须要找出递归的结束条件,不然的话,会一直调用自己,进入无底洞。也就是说,我们需要找出当参数为啥时,递归结束,之后直接把结果返回,请注意,这个时候我们必须能根据这个参数的值,能够直接知道函数的结果是什么。

例如,上面那个例子,当 n = 1 时,那你应该能够直接知道 f(n) 是啥吧?此时,f(1) = 1。完善我们函数内部的代码,把第二要素加进代码里面,如下

// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n == 1){
        return 1;
    }

有人可能会说,当 n = 2 时,那我们可以直接知道 f(n) 等于多少啊,那我可以把 n = 2 作为递归的结束条件吗?

当然可以,只要你觉得参数是什么时,你能够直接知道函数的结果,那么你就可以把这个参数作为结束的条件,所以下面这段代码也是可以的。

// 算 n 的阶乘(假设n>=2)
int f(int n){
    if(n == 2){
        return 2;
    }
}

注意我代码里面写的注释,假设 n >= 2,因为如果 n = 1时,会被漏掉,当 n <= 2时,f(n) = n,所以为了更加严谨,我们可以写成这样:

// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n <= 2){
        return n;
    }
}

第三要素:找出函数的等价关系式

第三要素就是,我们要不断缩小参数的范围,缩小之后,我们可以通过一些辅助的变量或者操作,使原函数的结果不变。

例如,f(n) 这个范围比较大,我们可以让 f(n) = n * f(n-1)。这样,范围就由 n 变成了 n-1 了,范围变小了,并且为了原函数f(n) 不变,我们需要让 f(n-1) 乘以 n。

说白了,就是要找到原函数的一个等价关系式,f(n) 的等价关系式为 n * f(n-1),即
f(n) = n * f(n-1)。
找出了这个等价,继续完善我们的代码,我们把这个等价式写进函数里。如下:

// 算 n 的阶乘(假设n不为0)
int f(int n){
    if(n <= 2){
        return n;
    }
    // 把 f(n) 的等价操作写进去
    return f(n-1) * n;
}

递归的缺陷

简单是递归的优点之⼀。但是递归调⽤会占⽤⼤量的系统堆栈,内存耗⽤多,在递归调⽤层次多时速度要⽐循环慢的多。所以在使⽤时要慎重。
**注意:任何可⽤递归解决的问题也能使⽤迭代解决。**但递归易于理解和调试。在不强调效率并且有⾜够的内存空间时,可以采⽤递归;在要求⾼性能的情况下尽量避免使⽤递归,递归调⽤既花时间⼜耗内存。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值