🐸 青蛙编程网
首页 / Java / Java 基础 / 6. 方法

方法(函数)

这是什么:方法(Method) = 把一段代码打包、起个名字,要用时喊一声,一次编写到处调用。

为什么用:代码写多了会发现,同一段逻辑到处复制粘贴,改一次得翻遍全文件。方法就像一台榨汁机:投进去水果,咔咔一顿转,倒出果汁;机器造一次,全家能用一年。

如何用:本章先学定义与调用,再练方法重载和变量作用域,最后弄清「参数只传复印件」这条 Java 规矩。

定义与调用

先照抄 main 的写法:public static 开头(这两个词的原理属于面向对象篇,现在照着写就行)。

public class MethodDemo {
    public static void main(String[] args) {
        greet("小明");            // 调用方法:喊名字 + 给参数
        greet("小红");

        int total = add(3, 5);    // 有返回值的方法,可以用变量接住
        System.out.println("3 + 5 = " + total);
    }

    // 无返回值:void,只干活不交结果
    static void greet(String name) {
        System.out.println("你好," + name + "!");
    }

    // 有返回值:int,干完活把结果交出去
    static int add(int a, int b) {
        return a + b;
    }
}

输出:

你好,小明!
你好,小红!
3 + 5 = 8
组成 例子 说明
参数 (String name) 干活需要的原料,可以没有
返回值类型 void / int void 表示不交结果;其他类型必须 return
return return a + b; 把结果交出去,方法立刻结束

把一个方法的"解剖图"完整标一遍,以后照着认:

部位 static int add(int a, int b) 干什么的
修饰符 static 入门阶段照抄(面向对象篇揭晓)
返回类型 int 承诺交回来的成品类型
方法名 add 调用时喊的名字,小驼峰
参数列表 (int a, int b) 原料清单:类型 + 名字,成对出现
方法体 { return a + b; } 真正的干活逻辑

调用时还有两个术语要对上号:定义时写的 a、b 叫形参(形式参数,占位用的),调用时给的 3、5 叫实参(实际参数,真材实料)。实参按位置一一对应塞给形参——第一个给第一个,第二个给第二个。

执行流程也值得在脑子里过一遍电影:程序在 main 里走到 add(3, 5),跳进 add 方法执行,return 把 8 交回来,跳回 main 原地继续往下走。方法就像"暂时离题去办件事,办完带着结果回来"。

方法重载:同名不同活

Java 允许方法名相同、参数不同的方法共存,这叫重载(overload):

static int add(int a, int b) {            // 两个 int 参数
    return a + b;
}

static double add(double a, double b) {   // 参数类型不同,算重载
    return a + b;
}

static int add(int a, int b, int c) {     // 参数个数不同,也算重载
    return a + b + c;
}

调用 add(1, 2) 走第一个,add(1.5, 2.5) 走第二个——Java 按你给的参数自动匹配。你天天在用的 System.out.println 能打印各种类型,就是靠一堆重载实现的。

重载的好处:一个动作一个名字。"加"就是 add,不管加的是 int 还是 double,不用记 addInt、addDouble 两个名字——调用者只管"我要加",类型匹配的杂活交给编译器。

重载的判定规则要划三条重点线:

情况 算不算重载
参数类型不同 ✅ 算
参数个数不同 ✅ 算
只有返回值类型不同,参数完全一样 ❌ 不算,编译报错

第三条最容易想岔:返回值是"结果",不是"身份"。光改返回类型,Java 在你调用 add(1, 2) 时根本不知道该去挑哪个,所以直接禁止这种重载。

更多方法练习

// 把摄氏度转成华氏度
static double celsiusToFahrenheit(double c) {
    return c * 1.8 + 32;
}

// 返回两个数中较大的那个
static int max(int a, int b) {
    if (a > b) {
        return a;
    }
    return b;
}

// 不传参数的问候
static void greet() {
    System.out.println("你好,陌生人!");
}

调用示例:

public static void main(String[] args) {
    System.out.println(celsiusToFahrenheit(37));   // 98.6
    System.out.println(max(3, 7));                  // 7
    greet();                                        // 你好,陌生人!
}

max 这个写法有个细节:两个 return 各管一边。a > b 成立就交出 a,方法立刻结束——所以后面那行 return b 只在不成立时才轮到执行。也有人喜欢写成三元一行流 return a > b ? a : b;,效果相同,挑顺眼的用。

方法里当然还能调用别的方法,方法调方法是搭积木的基本玩法:

// 判断是否及格,复用了上面的思想
static boolean isPass(int score) {
    return score >= 60;   // 比较表达式本身就是 boolean,直接交出去
}

注意 return score >= 60;——比较的结果就是 boolean,不用画蛇添足写 if 再 return true/false。让代码说短话,是方法章给你的第一个审美训练。

变量作用域:谁看得见谁

方法内声明的变量叫局部变量,只在本方法的大括号内有效:

static void methodA() {
    int x = 1;
    System.out.println(x);   // ✅ x 活在 methodA 里
}

static void methodB() {
    System.out.println(x);   // ❌ 编译报错,B 家没有 x 这个人
}

参数也是局部变量:形参 a、b 只活在 add 方法里,出了大括号就"下线"。不同方法里的同名变量互不相干——methodA 里有个 x,methodB 里也可以有个 x,它们是两个不同盒子。记住一条:变量活在自己所在的那对大括号里,流程控制章循环变量 i 出了循环就消失,也是同一条规则。

参数传递:Java 只传"复印件"

一个重要事实:把变量传进方法,方法内改它,外面的原值不变——Java 传的是值的复印件:

public class PassDemo {
    static void tryChange(int n) {
        n = 999;   // 改的只是复印件
    }

    public static void main(String[] args) {
        int num = 1;
        tryChange(num);
        System.out.println(num);   // 还是 1
    }
}

输出:

1

tryChange 收到的是 num 的一份拷贝,撕拷贝不影响原件。想"改了真能生效",就让方法返回新值,调用方接住重新赋值——这是入门阶段最清爽的思路。引用类型(如数组)传的虽然也是"复印件",但复印件上抄的是地址,所以能顺着地址改到原件内容,这层进阶理解放到面向对象篇再展开。

❓ 常见问题

Q1:方法一定要有返回值吗?

不是。返回值类型写 void 表示不返回任何东西,方法里只干活不交成品。

Q2:方法里能定义方法吗?

不能。Java 方法不能嵌套定义(除了局部类,进阶话题)。所有方法都写在类级别。

Q3:return 后面还能写代码吗?

可以写,但永远不会执行——return 后方法立刻结束,后面的代码是"死代码",编译器通常会警告。

Q4:main 方法为什么长成那个固定样子?

它是 JVM 钦点的程序入口,签名必须严格是 public static void main(String[] args),JVM 才认。你现在只需要知道:void 表示入口方法不交结果,String[] args 是命令行参数,其余交给面向对象篇。

Q5:什么是递归?现在要学吗?

方法调用自己就叫递归,比如"算 n 的阶乘 = n × (n-1) 的阶乘"。它优雅但烧脑,还容易写出自嘲式死循环,入门阶段知道有这回事即可,等你方法写得熟了再回头玩它。

⚠️ 新手翻车现场

翻车一:void 方法试图 return 一个值

static void sayHi() {
    return "你好";  // ❌ void 方法不能返回值
}

问题:void 表示不返回任何东西,return 后面不能跟值。

修正:改成 static String sayHi() { return "你好"; }。

翻车二:方法参数类型不匹配

static int add(int a, int b) => a + b;
add(3, "5");  // ❌ 编译报错:不能将 String 转换为 int

问题:Java 是强类型,参数类型必须严格匹配。

修正:add(3, 5),两个都是 int。

翻车三:有返回值的方法忘了 return

static int add(int a, int b) {
    a + b;  // ❌ 算了但没交出来,编译报错 "missing return statement"
}

问题:声明返回 int 的方法,必须有 return 把 int 交出去。

修正:return a + b;。

翻车四:指望方法改外面的变量

static void addOne(int n) {
    n = n + 1;
}

public static void main(String[] args) {
    int count = 10;
    addOne(count);
    System.out.println(count);   // 打印 10,不是 11!
}

问题:值传递——方法里改的是复印件,count 原件分毫不动。程序不报错,但结果和预期不符,属于"安静的 bug",比编译错误更磨人。

修正:让方法返回新值:count = addOne(count);,把"返回类型 int"配上 return n + 1;。

翻车五:重载只改了返回类型

static int calc(int a) { return a; }
static double calc(int a) { return a; }   // ❌ 编译报错:重复的方法

问题:两个方法名相同、参数完全相同,只有返回类型不同——这不构成重载,编译器无法区分调用谁。

修正:重载必须"参数列表长得不一样",或者干脆起不同的方法名。

🎯 什么时候用方法

  • 一段代码要被用两次及以上
  • 需要给代码起个有意义的名字,让 main 更易读
  • 想把复杂逻辑拆成小块,逐个测试

再加一条黄金判断法:当 main 读起来像流水账、超过一屏时,就该拆方法了。好的程序像目录——main 里一行一个动作("读输入、算结果、打报告"),细节都藏在名字起得清楚的方法里。别人读你的代码像读大纲,而不是像考古。

📝 本章小结

  • 方法 = 返回类型 + 方法名 + 参数列表 + 方法体
  • void 表示不返回值;其他类型必须 return
  • 形参是占位、实参是真料,按位置一一对应;Java 是值传递,方法内改参数不影响外面
  • 方法重载:同名不同参可共存,编译器按参数类型和个数挑选;只改返回值不算重载
  • 变量活在自己所在的大括号里,方法之间看不见彼此的局部变量
  • return 后方法立刻结束,后面代码不会执行
  • 记忆口诀:方法 = 名字 + 原料(参数)+ 成品(返回值);同名不同参,就是重载。

记忆锚点:方法是台自动贩卖机——按钮名是方法名,投币口是参数,出货口是返回值;投币规格不对机器不认(类型匹配),按了按钮不拿货白按(返回值要接住),void 机器只出声不出货。

动手改

  1. 写一个 static double celsiusToFahrenheit(double c),把摄氏度转华氏度(公式 c * 1.8 + 32)
  2. 给 greet 加一个重载版本:不传参数时说"你好,陌生人!"
  3. 写一个 static int max(int a, int b),返回两个数中较大的那个
  4. 把 celsiusToFahrenheit(37) 的结果打印出来,验证是 98.6
  5. 写 static boolean isPass(int score),并在 main 里用 59 和 60 各验证一次
  6. 写 static void printLine(int n),打印 n 个星号(循环拼接),体会 void 方法的用法

下一章:字符串,玩转最常用的数据 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。