目录
1、方法的概念及使用
1.1、什么是方法(method)
方法就是一个代码片段,类似于C语言中的 "函数"。方法存在的意义(不要背,重在体会):
1、是能够模块化的组织代码(当代码规模比较复杂的时候)。
2、做到代码被重复使用,一封代码可以再多个位置使用。
3、让代码更好的理解更简单。
4、直接调用现有的方法开发,不必重复造轮子。
1.2、方法的定义
方法语法格式
//方法定义
修饰符 返回值类型 方法名称([参数类型 形参.....]){方法体代码;
[return 返回值];
}
代码示例:实现一个函数,检测一个年份是否为闰年
public class Test {
public static boolean isLeapYear(int year){ //year是一个局部变量已经在这里定义了
// int year= 1900; 这里将它屏蔽是因为重复定义的问题
if((0 == year % 4 && 0 != year %100) || 0 == year % 400 ){
// System.out.println(year + "年是闰年");
return true;
}else{
// System.out.println(year + "你不是闰年");
return false;
}
}
public static void main(String[] args) {
boolean flg = isLeapYear(2022);
// System.out.println(flg);
}
}
总结:
1、传参时,实际参数的类型、参数个数、参数顺序要和形式参数一一匹配。
2、接收返回值的类型也要与方法返回值类型相同。
public static int add(int a,int b){
return a+b;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
int ret1 = add(1,2);//这里给a和b重新给值,为1和2
System.out.println("使用返回值:" + ret1);
int ret2 = add(a,b);
System.out.println("使用返回值:" + ret2);
int p = ret1*5;
System.out.println(p);
}
//结算结果为
//ret1为 3
//ret2为 30
//p为 15
一个方法从写好到用起来分几步?
- 定义一个方法,决定这个方法,返回值是什么类型?方法的名称叫啥?形参有几个?什么类型?什么类型?什么顺序?
- 使用这个方法,调用这个方法。方法名()————》看一下有几个参数,都有啥类型?都有啥顺序?
- 方法有返回值吗?要不要接收?拿什么接收?接收了返回值,我用返回值干什么?
注意事项:
1、修饰符:现阶段直接使用public static 固定搭配
2、返回值类型:如果方法有返回值,返回值类型必须要与返回的实体类型一致,如果没有返回值,必须写成void
3、方法名字:采用小驼峰命名
4、参数列表:如果方法没有参数,()中什么都不用写,如果有参数、需指定参数类型,多个参数之间使用逗号隔开
5、方法体:方法内部要执行的语句
6、再Java当中、方法必须写在类当中
7、再Java当中、方法不能嵌套定义
8、再Java当中、没有方法说明一说
1.3、方法调用的执行过程
【方法调用过程】
调用方法———>传递参数————>找到方法地址————>执行被调方法的方法体————>被调方法结束返回————>回到主调方法继续往下执行
注意事项:(方法的调用再栈上)
- 定义方法的时候,不会执行方法的代码,只有调用的时候才会执行。
- 一个方法可以被多次调用
代码示例1:j计算1!+2!+3!+4!+5!
public class Test {
public static void main(String[] args) {
int flg = 0;
for (int i = 1; i <= 5; i++) {//这里用循环是将fac生成的结果进行相加,形成1~5的阶
//乘的和
flg += fac(i);
}
System.out.println(flg);
}
//这个方法用来计算一个数字的阶乘
public static int fac(int n){
System.out.println("计算i的阶乘 n=" +n);
int num = 1;
for (int j = 1; j <=n ; j++) {
num *= j;
}
return num;
}
}
总结:
1、方法的调用是在栈上的
2、当方法遇到return或者遇到右花括号代表当前方法结束了。对应方法开辟的栈帧回收了。
1.4、实参和形参的关系(重要)
方法的形参相当于数学函数中的自变量。比如:1 + 2 + 3 + … + n的公式
Java中方法的形参就相当于sum函数中的自变量n,用来接收sum函数在调用时传递的值。形参的名字可以随意取,对方法都没有任何影响,形参只是在定义时需要借助的一个变量,用来保存方法在调用时传递过来的值。
public static int getSum(int N){ // N是形参
return (1+N)*N / 2;
}
getSum(10); // 10是实参,在方法调用时,形参N用来保存10
getSum(100); // 100是实参,在方法调用时,形参N用来保存100
public static int add(int a, int b){
return a + b;
}
add(2, 3); // 2和3是实参,在调用时传给形参a和b
了解一个代码:交换两个变量的值
来看一下这个代码能够实现吗?
public class TestMethod {
public static void main(String[] args) {
int a = 10;
int b = 20;
swap(a, b);
System.out.println("main: a = " + a + " b = " + b);
}
public static void swap(int x, int y) {
int tmp = x;
x = y;
y = tmp;
System.out.println("swap: x = " + x + " y = " + y);
}
}
结果显然是没有实现,原因是形参只是实参的一份临时拷贝,swap方法改变的是另一个空间的内容。
1.5、没有返回值的方法
方法的返回值是可选的. 有些时候是可以没有的,没有时返回值类型必须写成void
代码实例:
public 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);
}
}
2、方法的重载
在我们的日常用语中,"一词多义"的现象就叫做重载。
2.1、方法的重载概念
在Java中,如果多个方法的名字相同,参数列表不同,则称该几种方法被重载了。
代码实例:
public class Test {
public static int sum(int a,int b) {
return a+b;
}
public static double sum(double a,double b){
return a+b;
}
public static int sum(int a,int b,int c){
return a+b+c;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
int ret = sum(a,b);
System.out.println(ret);
double d1 = 12.4;
double d2 = 17.8;
double ret2 = sum(d1,d2);
System.out.println(ret2);
System.out.println(sum(1,2,3));
}
}
2.2、方法的签名
在同一个作用域中不能定义两个形同名称的标识符。比如:方法中不能定义两个名字一样的变量,那为什么类中就可以定义方法名相同的方法呢?
方法的签名即:经过编译器修改过之后方法最终的名字。具体方法:方法全路径名+参数列表+返回值类型,构成方法完整的名字。
代码示例:
public class Test {
public static int sum(int a,int b) {
return a+b;
}
public static double sum(double a,double b){
return a+b;
}
public static int sum(int a,int b,int c){
return a+b+c;
}
public static void main(String[] args) {
int a = 10;
int b = 20;
int ret = sum(a,b);
System.out.println(ret);
double d1 = 12.4;
double d2 = 17.8;
double ret2 = sum(d1,d2);
System.out.println(ret2);
System.out.println(sum(1,2,3));
}
上述代码进过编译之后,然后使用JDK自带的Javap反汇编工具查看,具体操作:
1、先对工程及逆行编译生成 .class 字节码文件
2、在控制台中进入到要查看的 .class 所在的目录
3、输入:javap -v 字节马文件名字即可
方法签名中的一些特殊符号说明:
特殊字符 | 数据类型 |
V | void |
Z | boolean |
B | byte |
C | char |
S | short |
I | int |
J | long |
F | float |
D | double |
[ | 数组(以[开头,配合其他的特殊字符,表述对应数据类型的数组,几个[表述几维数组) |
L | 应用类型,以L开头,以:结尾,中间是引用类型的全类名 |
3、递归
3.1、递归的概念
程序调用自身的编程技巧成为递归。
递归作为一种算法在程序设计语言中广泛使用。一个过程或函数在其定义或说明中有直接或间接调用其自身的一种方法。递归通常用于将一个复杂的问题层层转化为一个与原问题相似的规模小的问题来求解。
递归地运用只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大的减少了程序的代码量。
递归的只要思考方式在于:把大事化小
递归必要条件
1、将原问题划分为其子问题,注意:子问题必须要与原问题的解法相同
2、有一个终止条件
3、确定递推公式
代码演示:
public class Test {
public static int fac1(int n){
if(n == 1){
return 1;
}
int tmp = n * fac1(n - 1);
return tmp;
}
public static void main(String[] args) {
System.out.println(fac1(5));
}
图片演示过程:
关于"调用栈"
方法调用的时候, 会有一个 "栈" 这样的内存空间描述当前的调用关系. 称为调用栈.
每一次的方法调用就称为一个 "栈帧", 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息.后面我们借助 IDEA 很容易看到调用栈的内容.
3.2、递归练习
代码示例1:按照顺序大一一个数字的每一位(例如1234打印出 1 2 3 4)
public static void func20(int n){
if(n <= 9){
System.out.println(n % 10);
return;
}
func20(n/10);
System.out.println(n%10);
}
public static void main(String[] args) {
func20(1234);
}
代码示例2: 递归求 1 + 2 + 3 + ... + 10
public static int sum(int n) {
if(n == 1) {
return 1;
}
return n + sum(n - 1);
}
public static void main(String[] args) {
System.out.println(sum(10));
}