零基础带你入门Java(第三章:“方法”)
跟着我,带你从最基础的入门,打通 Java 基础的方法核心知识点
目录

一、什么是方法?
1. 方法的概念
方法,说白了就是一段可以重复使用的代码块,它能完成某个特定的功能。你可以把它理解成一个 "功能盒子",给它一些输入,它就给你一些输出(或者干脆不给输出,只干一件事)。
举个栗子:你想做蛋炒饭,每次都要写一遍 "洗锅→倒油→打鸡蛋→放米饭→放盐→翻炒" 这一大串步骤吗?当然不用!你可以把这些步骤打包成一个 "做蛋炒饭" 的方法,以后想吃了,直接调用这个方法就行!
2. 为什么要用方法?
那有人就问了:我直接把代码写在 main 里不行吗?为啥还要搞个方法出来多此一举?
问得好!用方法有三大好处:
|
好处 |
说明 |
|
代码复用 |
写一遍,用 N 遍!不用每次都复制粘贴 |
|
模块化 |
把大问题拆成小问题,每个方法解决一个小问题,思路更清晰 |
|
可读性 |
别人一看方法名就知道这一段是干啥的,不用读几百行代码 |
想象一下,如果一个 main 方法里写了 1000 行代码,你找 bug 不得找疯了?但如果拆成 10 个方法,每个方法 100 行,是不是就好找多了?
3. 和 C 语言函数对比

表情包开个玩笑哈哈哈,学过 C 语言的同学肯定发现了,Java 的 "方法" 不就是 C 语言的 "函数" 嘛!没错,本质上是一个东西,只是叫法不同而已。
我们来对比一下:
// C语言函数定义
int add(int a, int b) {
return a + b;
}
// C语言函数调用
int result = add(3, 5);、
// Java方法定义
public static int add(int a, int b) {
return a + b;
}
// Java方法调用
int result = add(3, 5);
看到没?几乎一模一样!
只是 Java 多了public static这两个修饰符而已。这俩修饰符现在你不用深究,记住写方法的时候加上就行,后面我们讲面向对象的时候再细说。
那有人就问了:C 语言里函数可以写在 main 外面,Java 也是这样吗?
没错!Java 的方法也必须写在类里面,但是和 main 方法是平级的,不能写在 main 里面哦!
二、方法的定义与调用
1. 基本语法格式
Java 方法的基本语法长这样:
修饰符 返回值类型 方法名(参数类型 参数名1, 参数类型 参数名2, ...) {
// 方法体
return 返回值;
}
我们来拆解一下:
修饰符:现在就写public static就行,固定搭配
返回值类型:方法执行完返回什么类型的数据,不返回就写void
方法名:和变量名一样,小驼峰命名,见名知意
参数列表:方法需要什么输入,没有就空着
return:返回结果,返回值类型是 void 的话可以不写
2. 无参无返回值方法
最简单的方法:既不需要输入,也不需要输出,就是干一件事。
// 定义一个打招呼的方法
public static void sayHello() {
System.out.println("Hello, Java!");
System.out.println("我是一个无参无返回的方法!");
}
public static void main(String[] args) {
// 调用方法
sayHello();
sayHello(); // 想调用几次就调用几次!
}
运行结果:
Hello, Java!
我是一个无参无返回的方法!
Hello, Java!
我是一个无参无返回的方法!
那有人就问了:我调用方法的时候,方法名后面的括号能不能省略?
当然不行,括号是方法的标志,哪怕没有参数,括号也必须写上,这是语法规定
3. 有参无返回值方法
需要输入,但不需要输出的方法。
// 定义一个打印n次Hello的方法
public static void printHello(int n) {
for (int i = 0; i < n; i++) {
System.out.println("Hello!");
}
}
public static void main(String[] args) {
printHello(3); // 打印3次
System.out.println("======分隔线======");
printHello(5); // 打印5次
}
运行结果:
Hello!
Hello!
Hello!
======分隔线======
Hello!
Hello!
Hello!
Hello!
Hello!
那有人就问了:我传参数的时候,类型必须和定义的一样吗?

必须的,定义的是 int,你就得传 int,传个 String 进去肯定报错。这就像你去自动售货机买水,人家要硬币,你塞张纸币进去,人家能认吗?一个道理。
4. 有参有返回值方法
既需要输入,也需要输出的方法。这是我们最常用的方法类型。
// 定义一个加法方法
public static int add(int a, int b) {
int sum = a + b;
return sum; // 把计算结果返回
}
// 定义一个求最大值的方法
public static int getMax(int a, int b) {
return a > b ? a : b; // 直接返回,不用中间变量也行
}
public static void main(String[] args) {
int result1 = add(3, 5);
System.out.println("3 + 5 = " + result1);
int result2 = getMax(10, 20);
System.out.println("最大值是:" + result2);
// 方法调用也可以直接当值用
System.out.println("100 + 200 = " + add(100, 200));
}
运行结果:
3 + 5 = 8
最大值是:20
100 + 200 = 300
那有人就问了:return 后面的代码还会执行吗?
不会!return 一执行,方法就立刻结束了,后面的代码根本不会跑。就像你在函数里写了 return 0; 后面的代码就都不执行了,和 C 语言一模一样!
5. 方法调用执行流程
很多新手搞不懂方法调用的时候,代码到底是怎么跑的。我给大家画个流程图:
main方法开始执行
↓
执行到方法调用语句
↓
【跳转到方法内部执行】
↓
执行完方法体 / 遇到return
↓
【跳回main方法,继续往下执行】
就像跳房子一样,跳过去执行完再跳回来。
三、方法重载
1. 什么是重载?

可能有人以为和重复有关系,但其实只能说有一点关系。
方法重载,就是同一个类中,方法名相同,但参数列表不同的多个方法。
说人话就是:同一个方法名,可以干不同的事。就像 "打印" 这个动作,可以打印文字,可以打印图片,可以打印 PDF,虽然都叫 "打印",但干的事不一样。
那有人就问了:为啥要搞重载?方法名不一样不行吗?
问得好!你想想,我们要做加法:
两个 int 相加叫 addInt
两个 double 相加叫 addDouble
三个 int 相加叫 addThreeInt
这也太麻烦了!都叫 add 不好吗?编译器自己根据参数判断该调用哪个。这就是重载的意义!
2. 重载规则
重载必须满足以下条件:
-
方法名必须相同(废话,不然叫啥重载)
-
参数列表必须不同(满足以下任意一条就行):
-
参数个数不同
-
参数类型不同
-
参数顺序不同
-
-
和返回值类型无关!(划重点,这是坑)
为啥和返回值无关?
因为调用方法的时候,你可以不接收返回值啊,比如add(3,5);,编译器怎么知道你要调用哪个返回值的方法?所以返回值不能作为重载的判断依据。
3. 重载示例代码
// 两个int相加
public static int add(int a, int b) {
System.out.println("调用了两个int的add");
return a + b;
}
// 三个int相加(个数不同)
public static int add(int a, int b, int c) {
System.out.println("调用了三个int的add");
return a + b + c;
}
// 两个double相加(类型不同)
public static double add(double a, double b) {
System.out.println("调用了两个double的add");
return a + b;
}
// int和double相加(顺序不同)
public static double add(int a, double b) {
System.out.println("调用了int+double的add");
return a + b;
}
public static void main(String[] args) {
System.out.println(add(3, 5)); // 调用两个int
System.out.println(add(1, 2, 3)); // 调用三个int
System.out.println(add(3.14, 2.56)); // 调用两个double
System.out.println(add(10, 3.14)); // 调用int+double
}
运行结果:
调用了两个int的add
8
调用了三个int的add
6
调用了两个double的add
5.7
调用了int+double的add
13.14
编译器自动根据你传的参数,选择正确的方法调用
四、方法参数传递
1. 值传递的概念
Java 的参数传递,只有一种方式:值传递。
什么是值传递?就是把实参的副本传进去,方法里修改的是这个副本,原来的实参不会变。
啥是实参啥是形参?
形参:方法定义时括号里的参数,比如add(int a, int b)里的 a 和 b
实参:调用方法时实际传进去的值,比如add(3, 5)里的 3 和 5
简单说:形参是方法的 "局部变量",实参是你传进去的 "值"。
2. 基本类型传递示例
先看基本类型(int、double、char 这些)的传递:
public static void change(int n) {
n = 100;
System.out.println("方法里的n:" + n);
}
public static void main(String[] args) {
int num = 10;
System.out.println("调用方法前的num:" + num);
change(num);
System.out.println("调用方法后的num:" + num);
}
运行结果:
调用方法前的num:10
方法里的n:100
调用方法后的num:10
方法里把 n 改成 100 了,但外面的 num 还是 10!因为传进去的是 num 的副本,改副本不影响本尊。
3. 引用类型传递示例
再看引用类型(数组、对象这些)的传递:
public static void changeArray(int[] arr) {
arr[0] = 100;
System.out.println("方法里的arr[0]:" + arr[0]);
}
public static void main(String[] args) {
int[] array = {1, 2, 3};
System.out.println("调用方法前的array[0]:" + array[0]);
changeArray(array);
System.out.println("调用方法后的array[0]:" + array[0]);
}
运行结果:
调用方法前的array[0]:1
方法里的arr[0]:100
调用方法后的array[0]:100
调用方法前的array[0]:1 方法里的arr[0]:100 调用方法后的array[0]:100
哎?怎么这次外面的值变了?那有人就问了:这不是引用传递吗?
不是!这还是值传递!
听我给你解释:数组变量存的不是数组本身,而是数组的地址。传参的时候,把这个地址的副本传进去了。虽然是副本,但副本和原件指向的是同一个数组啊!所以通过副本改数组,原件当然能看到变化。
这就像你家的地址是 "北京市 XX 路 XX 号",你把这个地址抄给朋友,朋友根据这个地址去你家,把你家电视砸了。你回家一看,电视是不是真的碎了?虽然你给的是地址的副本,但指向的是同一个房子啊!
记住:Java 只有值传递,没有引用传递! 引用类型传的是 "地址值" 的副本,本质还是值传递。
五、递归方法
1. 什么是递归?
递归,就是方法自己调用自己。
说人话就是:我调用我自己。
那有人就问了:自己调用自己?不会死循环吗?
问得好!所以递归必须有终止条件,不然就真的死循环了,最后栈溢出报错。
递归就像我们小时候听的故事:"从前有座山,山里有座庙,庙里有个老和尚讲故事,讲的是从前有座山..." 这个故事没有终止条件,所以能讲一天一夜...
2. 递归三要素
写递归必须满足三个条件:
-
终止条件:递归什么时候停下来?(必须有!)
-
递归公式:大问题怎么拆成小问题?
-
收敛方向:每次递归都要更接近终止条件
3. 阶乘递归示例
最经典的递归例子:求 n 的阶乘。
阶乘公式:n! = n × (n-1)! 终止条件:1! = 1
public static int factorial(int n) {
// 终止条件
if (n == 1) {
return 1;
}
// 递归公式:n! = n * (n-1)!
return n * factorial(n - 1);
}
public static void main(String[] args) {
System.out.println("5! = " + factorial(5));
System.out.println("3! = " + factorial(3));
}
运行结果:
5! = 120
3! = 6
我们来拆解一下 factorial (5) 的执行过程:
factorial(5) = 5 * factorial(4)
factorial(4) = 4 * factorial(3)
factorial(3) = 3 * factorial(2)
factorial(2) = 2 * factorial(1)
factorial(1) = 1 (遇到终止条件,开始返回)
factorial(2) = 2 * 1 = 2
factorial(3) = 3 * 2 = 6
factorial(4) = 4 * 6 = 24
factorial(5) = 5 * 24 = 120
看到没?先一层层往下拆,拆到最底层再一层层往上算,这就是递归的执行过程。
4. 递归的优缺点
|
优点 |
缺点 |
|
代码简洁,思路清晰 |
效率低,有大量重复计算 |
|
适合解决有递归性质的问题 |
容易栈溢出(递归深度太大) |
|
很多算法天然就是递归的 |
不好调试,出问题很难找 |
那有人就问了:递归这么多缺点,为啥还要用?
因为有些问题用递归写太简单了!比如汉诺塔问题,用递归写几行就搞定了,用循环写能写死你...

但是记住:斐波那契千万不要用递归算 n=40 以上的数,慢到你怀疑人生!因为有大量重复计算!
汉诺塔可以去看看我的算法思考有一期讲了。
六、总结~
本章重点回顾:
方法就是可复用的代码块,本质和 C 语言的函数一样
方法分三种:无参无返回、有参无返回、有参有返回
方法重载:同名不同参,C 语言不支持这个特性
Java 只有值传递! 基本类型传值副本,引用类型传地址副本
递归三要素:终止条件、递归公式、收敛方向
经典坑点:基本类型的交换方法不生效,因为改的是副本
诸位共勉,无限学习!

更多推荐


所有评论(0)