javaSE中方法的使用
一、方法的基本用法
1.1、什么是方法?????
方法就是一个代码片段. 类似于 C 语言中的 “函数”
方法存在的意义:
1. 是能够模块化的组织代码(当代码规模比较复杂的时候).
2. 做到代码被重复使用, 一份代码可以在多个位置使用.
3. 让代码更好理解更简单.
4. 直接调用现有方法开发, 不必重复造轮子
先看一个代码:1! + 2! + 3! + 4! + 5!
public class TestDome {
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 5; i++) {
int ret = 1;
for (int j = 1; j <= i; j++) {
ret = ret * j;
}
sum = sum + ret;
}
System.out.println(sum);
}
}
在这个代码中有两个循环,嵌套起来的,比较容易写错,我们就可以使用方法来优化
public class TestDome {
public static int sum(int i){
int ret = 1;
for (int j = 1; j <= i; j++) {
ret = ret * j;
}
return ret;
}
public static void main(String[] args) {
int sum = 0;
for (int i = 1; i <= 5; i++) {
sum = sum + sum(i);
}
System.out.println(sum);
}
}
计算1! + 2! + 3! + 4! + 5!,首先要得到一个数的阶乘,然后让他们相加,才能得到1! + 2! + 3! + 4! + 5!的和,所以就用了一个sum方法,得到一个数的阶乘,这就是方法的功能(得到一个数的阶乘)
1.2、方法定义语法
//方法定义
public static 返回值 方法名称(参数类型 形参…){
方法体代码:
return 返回值;
}
例如:
public static int sum(int i){
int ret = 1;
for (int j = 1; j <= i; j++) {
ret = ret * j;
}
return ret;
}
代码示例: 实现一个方法实现两个整数相加
注意事项
- public 和 static 两个关键字在此处具有特定含义, 我们暂时不讨论, 后面会详细介绍.
- 方法定义时, 参数可以没有. 每个参数要指定类型
- 方法定义时, 返回值也可以没有, 如果没有返回值, 则返回值类型应写成 void
- 方法定义时的参数称为 “形参”, 方法调用时的参数称为 “实参”.
- 方法的定义必须在类之中, 代码书写在调用位置的上方或者下方均可.
- Java 中没有 “函数声明” 这样的概念
1.3 方法调用的执行过程
基本规则
定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行.
当方法被调用的时候, 会将实参赋值给形参.
参数传递完毕后, 就会执行到方法体代码.
当方法执行完毕之后(遇到 return 语句), 就执行完毕, 回到方法调用位置继续往下执行
一个方法可以被多次调用
1.4 实参和形参的关系(重要)
代码示例: 交换两个整型变量:
对于基础类型来说, 形参相当于实参的拷贝. 即 传值调用。
可以看到实参的值传给形参,但是形参的值是不会改变实参的,因为调用方法的时候在内存上开辟了一个空间给形参,当程序执行完方法时这块空间就自动销毁了,然而实参的值依旧没有改变。
解决办法: 传引用类型参数 (例如数组来解决这个问题)
class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
swap(a, b);
System.out.println("a = " + a + " b = " + b);
}
public static void swap(int x, int y) {
int tmp = x;
x = y;
y = tmp;
}
}
1.5 没有返回值的方法
方法的返回值是可选的. 有些时候可以没有的;
class Test {
public static void main(String[] args) {
int a = 10;
int b = 20;
print(a, b);
}
public static void print(int x, int y) {
System.out.println("x = " + x + " y = " + y);
}
}
二、方法的重载
有些时候我们需要用一个函数同时兼容多种参数的情况, 我们就可以使用到方法重载
针对同一个类:
方法名相同
方法的参数不同(参数个数或者参数类型)
方法的返回值类型不影响重载
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;
}
public static void main(String[] args) {
int a1 = 10;
int b1 = 20;
System.out.println(Add(a1,b1));
double a2 = 10.1;
double b2 = 20.5;
System.out.println(Add(a2,b2));
double a3 = 10.1;
double b3 = 20.5;
double c3 = 50.8;
System.out.println(Add(a3,b3,c3));
}
方法的名字都叫 add. 但是有的 add 是计算 int 相加, 有的是 double 相加; 有的计算两个数字相加, 有的是计算三个数字相加.
同一个方法名字, 提供不同版本的实现, 称为 方法重载
三、方法递归
一个方法在执行过程中调用自身, 就称为 “递归”.
递归相当于数学上的 “数学归纳法”, 有一个起始条件, 然后有一个递推公式.
例如, 我们求 N!
起始条件: N = 1 的时候, N! 为 1. 这个起始条件相当于递归的结束条件.
递归公式: 求 N! , 直接不好求, 可以把问题转换成 N! => N * (N-1)!
代码示例: 求斐波那契数列的第 N 项
public static int fB(int n){
if(n == 1 || n ==2){
return 1;
}
return fB(n-1) + fB(n - 2);
}
public static void main(String[] args) {
//递归求斐波那契数列的第 N 项 1 1 2 3 5 8 13.....
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int ret = fB(n);
}
递归求 N 的阶乘:
public class TestDome {
public static int sumD(int n){
if(n == 1){
return 1;
}
return n * sumD(n-1);
}
public static void main(String[] args) {
//递归求 N 的阶乘
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
System.out.println(sumD(n));
}
}
我们来看一下这个是怎么执行的:
例如:求1!+2!+3!
当n == 3的时候,执行 return n * sumD(n-1) , 这时有调用方法执行sumD(n-1)(这时候n == 2), 然后执行 return n * sumD(n-1),又调用方法执行sumD(n-1)(这时候 n == 1)执行 return 1;
返回的1
关于 “调用栈”
方法调用的时候, 会有一个 “栈” 这样的内存空间描述当前的调用关系. 称为调用栈.
每一次的方法调用就称为一个 “栈帧”, 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息.
后面我们借助 IDEA 很容易看到调用栈的内容
3.4 递归小结
递归是一种重要的编程解决问题的方式.
有些问题天然就是使用递归方式定义的(例如斐波那契数列, 二叉树等), 此时使用递归来解就很容易.
有些问题使用递归和使用非递归(循环)都可以解决. 那么此时更推荐使用循环, 相比于递归, 非递归程序更加高效