Java 方法基础

背景与动机#

方法用于把一段可复用逻辑封装起来,让程序从“堆在 main 里的一串语句”变成“按职责组织的小块逻辑”。

学方法时,重点不是只会写语法,而是理解:

  1. 方法如何接收参数。
  2. 方法如何返回结果。
  3. 方法重载如何区分。
  4. 重载和重写到底有什么区别。
  5. Java 参数传递到底传的是什么。

核心原理拆解#

1. 方法定义#

基本格式:

返回值类型 方法名(参数列表) {
方法体
}

例如:

static int add(int a, int b) {
return a + b;
}

这里 add 接收两个 int 参数,返回一个 int 结果。

可变参数

可变参数用类型...定义,可变参数相当于数组类型:

class Group {
private String[] names;
public void setNames(String... names) {
this.names = names;
}
}
Group g = new Group();
g.setNames("Xiao Ming", "Xiao Hong", "Xiao Jun"); // 传入3个String
g.setNames("Xiao Ming", "Xiao Hong"); // 传入2个String
g.setNames("Xiao Ming"); // 传入1个String
g.setNames(); // 传入0个String

2. 没有返回值使用 void#

static void printHello() {
System.out.println("hello");
}

void 表示方法不返回结果。

3. return 结束方法并返回值#

static int max(int a, int b) {
if (a > b) {
return a;
}
return b;
}

对于有返回值的方法,所有执行路径都必须能返回对应类型的结果。

4. 方法重载#

同一个类中,方法名相同但参数列表不同,叫方法重载:

static int add(int a, int b) {
return a + b;
}
static double add(double a, double b) {
return a + b;
}

重载只看方法名和参数列表,不靠返回值区分。

5. 重载和重写不是一回事#

很多初学者会把“重载”和“重写”混在一起,但它们解决的是两个不同的问题。

  • 重载:同一个类里,方法名相同,参数列表不同。
  • 重写:子类继承父类后,用相同的方法签名重新实现父类行为。

一个看参数列表,一个看继承关系。

class Animal {
void speak() {
System.out.println("animal");
}
}
class Dog extends Animal {
@Override
void speak() {
System.out.println("wang");
}
}
public class MethodCompare {
static int add(int a, int b) {
return a + b;
}
static int add(int a, int b, int c) {
return a + b + c;
}
}

上面 addadd 是重载,因为参数个数不同;Dog.speak()Animal.speak() 是重写,因为子类覆盖了父类同签名方法。

可以先记一个最实用的判断法:

  • 同一个类里同名不同参,通常是在说重载。
  • 父子类之间同名同参,通常是在说重写。

6. Java 参数传递是值传递#

Java 方法参数传递的是变量值的副本。

基本类型传的是具体值的副本;引用类型传的是引用值的副本。引用类型参数可以通过这个引用修改对象内部状态,但不能让调用方变量改指向另一个对象。

这里最容易卡住的点是:Java 里没有 C 或 C++ 那种“把指针本身当参数语法直接暴露出来”的写法,所以通常不说 Java 有“指针传参”。更准确的说法是:

  • Java 只有值传递。
  • 如果参数是基本类型,复制的是数值本身。
  • 如果参数是引用类型,复制的是引用值。

也就是说,方法拿到的永远只是一个副本,只不过这个副本有时是 10,有时是“指向某个对象的引用值”。

下面这个例子把“修改对象内容”和“修改引用指向”放在一起看,会更清楚:

class User {
String name;
int age;
User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class PassDemo {
public static void main(String[] args) {
User user = new User("Tom", 20);
changeUser(user);
System.out.println(user.name + ", " + user.age);
}
static void changeUser(User ref) {
ref.age = 30;
ref = new User("Jerry", 18);
}
}

输出仍然是:

Tom, 30

原因分两步看:

  1. ref.age = 30 改的是原对象内部状态,所以调用方能看到变化。
  2. ref = new User("Jerry", 18) 改的是参数副本自己的指向,不会改掉 mainuser 变量本身。

生成结果 1
生成结果 1

最小可运行代码示例#

public class MethodDemo {
public static void main(String[] args) {
System.out.println(add(1, 2));
System.out.println(add(1.5, 2.5));
int n = 10;
changeNumber(n);
System.out.println(n);
}
static int add(int a, int b) {
return a + b;
}
static double add(double a, double b) {
return a + b;
}
static void changeNumber(int value) {
value = 99;
}
}

输出中 n 仍然是 10,因为方法里修改的是参数副本。

常见陷阱与错误示例#

1. 以为返回值不同就能重载#

错误示例:

static int get() {
return 1;
}
static String get() {
return "1";
}

方法重载不能只靠返回值类型区分。

2. 有返回值的方法遗漏 return#

错误示例:

static int max(int a, int b) {
if (a > b) {
return a;
}
}

a <= b 时没有返回值,编译器会报错。

3. 误以为引用参数能改变调用方变量指向#

方法能通过引用修改对象内容,但不能通过给参数重新赋值来改变调用方变量本身。

4. 把重写和重载混为一谈#

重载发生在同一个类中,核心是参数列表不同;重写发生在继承体系中,核心是子类重新实现父类已有方法。二者名字相近,但判断依据完全不同。

面试高频问题#

1. 什么是方法重载#

同一个类中方法名相同、参数列表不同的方法构成重载。参数列表包括参数个数、类型和顺序。

2. 方法重载能不能只靠返回值区分#

不能。调用方法时编译器主要根据方法名和参数列表选择目标方法,不能只靠返回值判断。

3. 重载和重写的区别是什么#

重载是同一个类里同名不同参的方法;重写是子类对父类同签名方法的重新实现。重载主要体现编译期的方法选择,重写主要体现运行期的多态分派。

4. Java 是值传递还是引用传递#

Java 是值传递。引用类型参数传递的是引用值的副本,不是变量本身。

5. Java 有没有指针传参#

通常不这样说。Java 没有对开发者暴露 C 或 C++ 那种可直接操作的指针参数语法。更准确的表述是:Java 只有值传递,引用类型参数传递的是引用值的副本。

一句话总结#

Java 方法用于封装可复用逻辑;重载看同名不同参,重写看父子类同签名覆盖;参数传递本质上始终是值传递,引用类型也只是传递引用值的副本。

文章目录

文章目录