1.方法的概念和使用
1.1 为什么需要方法
假设你是班长,学生需要到学校的某个地方领书。但是学生都不知道领书地在哪里,于是学生都纷纷在QQ私聊上来问你,一会儿来一个 一会儿又来一个,每一个学生都是来问领书地的,然后你的回答都是教学楼门口领书。每一次都是一样的回答,但是又要一直这样回复,这样就显得很麻烦。
那有什么方法可以解决这个重复又麻烦的问题了?
答:可以直接在QQ班级群发在 教学楼门口 领书,这样班级里的同学都可以看到了。要是还有人问你,你就可以让他去看QQ群,这样就可以解决这个问题了
上述的问题例子就充分了解为什么需要方法了
因此,在编程中,我们也可以将频繁使用的代码封装成方法,需要时直接拿来方法名使用即可,避免了一遍一遍的重复,这样不仅能让代码不冗余,还能提高代码的可读性
1.2 方法的概念
方法就相当于C语言中的函数,具有独立性,可以独立完成某个功能,只要调用这个方法就可以完成这个功能
是能够模块化的组织代码(当代码规模比较复杂的时候).
做到代码被重复使用, 一份代码可以在多个位置使用.
让代码更好理解更简单.
比如:输入一个年份,判断是否为闰年?
import java.util.Scanner;
public class Test { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int year = scanner.nextInt(); if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { System.out.println("yes"); } else { System.out.println("no"); } } }
上述代码 if else 就是判断是否为闰年的,那接下来我们就将判断闰年的代码封装成方法
import java.util.Scanner; public class Test { public static void isLeapYear(int year) { if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { System.out.println("yes"); } else { System.out.println("no"); } } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int year = scanner.nextInt(); isLeapYear(year); } }
这样就将判断闰年的代码封装成方法了,这样主函数看起了就比较简洁了。当我们在主函数中看到了 isLeapYear(year) 我们就知道了需要调用 isLeapYear 这个方法了。
方法语法格式:
public:公共的,后期会讲
static:静态的
void:无返回值
形参可以为空,要是有形参,必须得传实参。要是有多个形参,就得传多个实参,传的顺序一一对应,多个形参需要用逗号隔开
方法名采用小驼峰命名规范
在java当中,方法必须写在类当中
在java当中,没有方法声明
通过函数名(实参)进行调用
定义方法的时候, 不会执行方法的代码. 只有调用的时候才会执行
一个方法可以被多次调用
代码从主函数开始执行,主函数结束。当在主函数中执行到 isLeapYear(year) 这个代码时,我们就知道需要调用这个函数了,把 主函数中的 year 值 传给了形参中的 year(注:此形参非彼形参),然后执行这个函数,执行完后返回到主函数中继续执行主函数
方法的好处:
当下面的代码还要使用这个方法时,可以直接调用,不需要重复去写这些代码
方法调用过程:
调用方法--->传递参数--->找到方法地址--->执行被调方法的方法体--->被调方法结束返回--->回到主调方法继续往下执行
1.3 实参 和 形参 的关系
方法的形参相当于数学函数中的自变量, 比如:y = x + 1
形参就相当 x ,用来接收 实参 传过来的值。当传过来的实参值不一样时, y 最后的值也是不一样的
形参的名字可以随意取,对方法都没有任何影响,形参只是方法在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值
public class Test { public static int gainX(int x) { return x + 1; } public static void main(String[] args) { System.out.println(gainX(100)); } }
x 就是一个 形参,用于接收实参的值,实参就是100,负责给形参传值
在Java中,实参的值永远都是拷贝到形参中,形参和实参本质是两个实体
证明形参和实参本质是两个实体:
public class Test { public static void swap(int x,int y) { System.out.println(x); System.out.println(y); int tmp = x; x = y; y =tmp; System.out.println(x); System.out.println(y); } public static void main(String[] args) { int a = 10; int b = 20; swap(a,b); System.out.println(a); System.out.println(b); } }
运行结果:
a = 10,b = 20,然后调用swap方法,将 a 的值传给了形参 x ,将 b 的值传给了形参 y。然后执行swap 方法体,打印 x 和 y ,因为是将 a 和 b的值 传给了 x 和 y 所以打印的 x 是 10,y 是 20,然后交换 x 和 y 里面的值,然后在打印交换后的 x 和 y, x 是 20,y 是 10,执行完swap方法后,回到主函数继续执行主函数剩下的代码,打印 a 和 b ,因为 形参 和 实参 是两个独立的实体,形参的改变不影响实参,所以打印的 a 还是 10,b 还是 20
那怎么样才能让形参的改变同时也影响的实参了?
答:因为方法最多只能返回一个值,所以有时候不得不让形参的改变同时也影响着实参,解决办法就是传数组给形参。(大家目前只做了解,后期博文里面会讲)
1.4 有返回值的方法和没有返回值的方法
方法可以有返回值,也可以没有返回值。当没有返回值时,我们就把方法的返回类型写成 void 就表示无返回值
①有返回值的方法
public class Test { public static int summation(int n) { int sum = 0; for (int i = 1; i <= n; i++) { sum += i; } return sum; } public static void main(String[] args) { int a = 10; int sum = summation(a); System.out.println(sum); } }
这个代码就是求1 ~ n 的和的代码,传一个值给 summation 这个方法它就将 1 到 这个值之间的所以数加起来,返回通过 return 返回一个int类型的值,我们用一个int类型的变量接收即可
②无返回值的方法
public class Test { public static void print(int n) { if (n >= 10) { System.out.println("大于等于10"); } else { System.out.println("小于10"); } } public static void main(String[] args) { int a = 10; print(a); } }
这个代码就是判断一个数是否大于等于10或者小于10,传一个数给 print 方法它自动判断,然后直接打印,不会返回任何结果
2.方法重载
2.1 为什么需要方法重载
假设我们有一个方法是专门用来求两个数的和,那它的形参类型我们应该设置为什么?
答: 如果设置为 整型,就不能处理浮点型了,设置为浮点型就不能处理整型了,所以我们通常会写功能一样但是形参类型不一样的方法,这样就可以处理不同类型变量了。这样就会面对这样一个问题,功能一样,形参类型不一样,那如果其中一个方法名叫 sum,那另一个方法名叫什么咧?所以就有了方法重载
2.2 方法重载的概念
方法重载:如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了
方法重载的好处:当一些方法功能一样,但是形参列表不一样时,我们可以使用同一个方法名
public class Test { public static int sum(int num1,int num2) { return num1 + num2; } public static double sum(double num1,double num2) { return num1 + num2; } public static void main(String[] args) { int a = 10; int b = 20; int c = sum(a,b); System.out.println(c); double d = 2.1; double e = 1.5; double f = sum(d,e); System.out.println(f); } }
上述代码中的两个 sum 方法就形成了重载
从上述代码中,我们可以了解方法重载的三要素:
方法名必须相同
参数列表必须不同(参数的个数不同、参数的类型不同、类型的次序必须不同)
与返回值类型是否相同无关
方法中不能定义两个名字一样的变量,那为什么类中就可以定义方法名相同的方法呢?
答:因为方法是要经过方法签名的(经过编译器编译修改过之后方法最终的名字),具体方式:方法全路径名+参数列表+返回值类型,构成方法完整的名字。所以参数列表不同,最后构成的方法完整名字也是不同的
3.递归
3.1递归的概念
递归 顾名思义 递 反复执行一个方法,当条件不满足时就得 归 了
举例:
从前有坐山,山上有座庙,庙里有个老和尚给小和尚将故事,讲的就是:
从前有座山,山上有座庙,庙里有个老和尚给小和尚讲故事,讲的就是:
"从前有座山,山上有座庙..."
那么 这个故事结束的条件就是老和尚睡着或者小和尚睡着
上面故事中的特征就是自身中又包含了自己
递归:一个方法在执行的过程中调用自身,就称为“递归”
递归必要的条件:
原问题中必须包含子问题(注意:子问题的解法必须和原问题的解法一样)
递归出口
我们遇到的问题直接并不好解决,但是发现将原问题拆分成其子问题之后,子问题与原问题有相同的解法,等子问题解 决之后,原问题就迎刃而解了
public class Test { public static int fac(int n) { if (n == 1) { return 1; } else { return n * fac(n - 1); } } public static void main(String[] args) { int n = 3; int ret = fac(n); System.out.println(ret); } }
上述代码就是就求 n 的阶乘的问题,这个代码的 fac 方法就用了递归的思想。
关于 "调用栈"
方法调用的时候, 会有一个 "栈" 这样的内存空间描述当前的调用关系. 称为调用栈.
每一次的方法调用就称为一个 "栈帧", 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息
注:要是递归次数太多就会造成栈溢出, 那么就应该采用迭代
注:递归一定要有出口,否则会造成栈溢出