---
title: "05-变量与方法"
aliases:
- "变量与方法"
created: 2025-12-24
---
# 变量与方法
---
## 一、变量详解
### **1.1 变量分类**
```drawio
```
Java
```java
public class VariableDemo {
// ═══════════════════════════════════════════════════════════════════
// 类变量(静态变量):属于类,所有实例共享
// ═══════════════════════════════════════════════════════════════════
private static int classCount = 0; // 类变量
public static final String APP_NAME = "MyApp"; // 静态常量
// ═══════════════════════════════════════════════════════════════════
// 成员变量(实例变量):属于对象,每个实例独立
// ═══════════════════════════════════════════════════════════════════
private String name; // 实例变量
private int age; // 实例变量
public void method(int param) { // param 是局部变量
// ═══════════════════════════════════════════════════════════════
// 局部变量:定义在方法内部
// ═══════════════════════════════════════════════════════════════
int localVar = 10; // 局部变量
String message; // 局部变量(未初始化,使用前必须赋值)
for (int i = 0; i < 10; i++) { // i 也是局部变量
// ...
}
// 代码块内的局部变量
{
int blockVar = 20; // 作用域仅限于这个代码块
}
// blockVar 在这里不可见
}
}
```
### **1.2 三种变量详细对比**
```drawio
```
### **1.3 变量存储位置图解**
```drawio
```
### **1.4 为什么成员变量有默认值**
```drawio
```
```java
public class DefaultValueDemo {
// 成员变量有默认值
private int count; // 默认 0
private String name; // 默认 null
private boolean active; // 默认 false
private int[] array; // 默认 null
public void showDefaults() {
System.out.println("count: " + count); // 0
System.out.println("name: " + name); // null
System.out.println("active: " + active); // false
System.out.println("array: " + array); // null
}
public void localVariableDemo() {
int localVar;
// System.out.println(localVar); // ❌ 编译错误:变量未初始化
localVar = 10; // 必须先赋值
System.out.println(localVar); // ✅ 正确
}
}
```
### **1.5 静态变量的作用**
Java
```java
public class Counter {
// 静态变量:所有实例共享
private static int totalCount = 0;
// 实例变量:每个实例独立
private int instanceId;
public Counter() {
totalCount++;
instanceId = totalCount;
}
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
System.out.println("c1.instanceId: " + c1.instanceId); // 1
System.out.println("c2.instanceId: " + c2.instanceId); // 2
System.out.println("c3.instanceId: " + c3.instanceId); // 3
// 静态变量通过类名访问
System.out.println("totalCount: " + Counter.totalCount); // 3
}
}
```
```drawio
```
---
---
## 二、方法详解
### **2.1 方法的分类**
```drawio
```
```java
public class MethodDemo {
private int count = 0;
// ═══════════════════════════════════════════════════════════════════
// 1. 无参无返回值
// ═══════════════════════════════════════════════════════════════════
public void printHello() {
System.out.println("Hello");
}
// ═══════════════════════════════════════════════════════════════════
// 2. 有参无返回值
// ═══════════════════════════════════════════════════════════════════
public void printMessage(String message) {
System.out.println(message);
}
// ═══════════════════════════════════════════════════════════════════
// 3. 无参有返回值
// ═══════════════════════════════════════════════════════════════════
public int getCount() {
return count;
}
// ═══════════════════════════════════════════════════════════════════
// 4. 有参有返回值
// ═══════════════════════════════════════════════════════════════════
public int add(int a, int b) {
return a + b;
}
// ═══════════════════════════════════════════════════════════════════
// 5. 静态方法
// ═══════════════════════════════════════════════════════════════════
public static int max(int a, int b) {
return a > b ? a : b;
}
}
```
### **2.2 静态方法 vs 实例方法**
```drawio
```
```java
public class MethodAccessDemo {
private int instanceVar = 10; // 实例变量
private static int staticVar = 20; // 静态变量
// ═══════════════════════════════════════════════════════════════════
// 静态方法
// ═══════════════════════════════════════════════════════════════════
public static void staticMethod() {
System.out.println(staticVar); // ✅ 可以访问静态变量
// System.out.println(instanceVar); // ❌ 不能访问实例变量
// System.out.println(this.instanceVar); // ❌ 不能使用 this
anotherStaticMethod(); // ✅ 可以调用静态方法
// instanceMethod(); // ❌ 不能调用实例方法
}
public static void anotherStaticMethod() {
System.out.println("另一个静态方法");
}
// ═══════════════════════════════════════════════════════════════════
// 实例方法
// ═══════════════════════════════════════════════════════════════════
public void instanceMethod() {
System.out.println(instanceVar); // ✅ 可以访问实例变量
System.out.println(staticVar); // ✅ 可以访问静态变量
System.out.println(this.instanceVar); // ✅ 可以使用 this
staticMethod(); // ✅ 可以调用静态方法
anotherInstanceMethod(); // ✅ 可以调用实例方法
}
public void anotherInstanceMethod() {
System.out.println("另一个实例方法");
}
public static void main(String[] args) {
// 静态方法调用
MethodAccessDemo.staticMethod(); // 推荐:类名.方法名
staticMethod(); // 同一个类中可省略类名
// 实例方法调用
MethodAccessDemo demo = new MethodAccessDemo();
demo.instanceMethod(); // 必须通过对象调用
}
}
```
**为什么静态方法不能访问非静态成员?**
```drawio
```
### **2.3 方法重载(Overload)**
```drawio
```
```java
public class OverloadDemo {
// ═══════════════════════════════════════════════════════════════════
// ✅ 正确的重载
// ═══════════════════════════════════════════════════════════════════
// 参数个数不同
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
// 参数类型不同
public double add(double a, double b) {
return a + b;
}
public String add(String a, String b) {
return a + b;
}
// ═══════════════════════════════════════════════════════════════════
// ❌ 错误的重载
// ═══════════════════════════════════════════════════════════════════
// 只有返回值不同,不构成重载
// public double add(int a, int b) { // ❌ 编译错误
// return a + b;
// }
// 只有参数名不同,不构成重载
// public int add(int x, int y) { // ❌ 编译错误
// return x + y;
// }
public static void main(String[] args) {
OverloadDemo demo = new OverloadDemo();
// 编译器根据参数类型和个数选择合适的方法
System.out.println(demo.add(1, 2)); // 调用 add(int, int)
System.out.println(demo.add(1, 2, 3)); // 调用 add(int, int, int)
System.out.println(demo.add(1.5, 2.5)); // 调用 add(double, double)
System.out.println(demo.add("Hello", "!")); // 调用 add(String, String)
}
}
```
**重载的编译期绑定**:
```drawio
```
### **2.4 方法重写(Override)**
```drawio
```
```java
class Animal {
protected String name;
public void eat() {
System.out.println("动物吃东西");
}
public Animal getAnimal() {
return new Animal();
}
// private 方法不能被重写
private void privateMethod() {
System.out.println("私有方法");
}
// final 方法不能被重写
public final void finalMethod() {
System.out.println("final方法");
}
// static 方法不是重写,是隐藏
public static void staticMethod() {
System.out.println("Animal的静态方法");
}
}
class Dog extends Animal {
// ═══════════════════════════════════════════════════════════════════
// ✅ 正确的重写
// ═══════════════════════════════════════════════════════════════════
@Override
public void eat() { // 方法名、参数列表相同
System.out.println("狗吃骨头");
}
// 协变返回类型:返回值可以是父类返回值的子类
@Override
public Dog getAnimal() { // 返回 Dog 是 Animal 的子类
return new Dog();
}
// ═══════════════════════════════════════════════════════════════════
// ❌ 错误的重写
// ═══════════════════════════════════════════════════════════════════
// 不能缩小访问权限
// @Override
// void eat() { } // ❌ default < protected
// 不能重写 final 方法
// @Override
// public void finalMethod() { } // ❌ 编译错误
// static 方法是隐藏,不是重写
public static void staticMethod() { // 没有 @Override
System.out.println("Dog的静态方法");
}
}
```
```drawio
```
### **2.5 可变参数(Varargs)**
```drawio
```
```java
public class VarargsDemo {
// ═══════════════════════════════════════════════════════════════════
// 可变参数方法
// ═══════════════════════════════════════════════════════════════════
public int sum(int... numbers) {
// numbers 本质是 int[] 数组
int total = 0;
for (int num : numbers) {
total += num;
}
return total;
}
// 可变参数必须在最后
public void print(String prefix, String... messages) {
for (String msg : messages) {
System.out.println(prefix + msg);
}
}
// ❌ 错误:可变参数不是最后一个
// public void wrong(String... messages, String suffix) { }
// ❌ 错误:多个可变参数
// public void wrong(String... a, int... b) { }
public static void main(String[] args) {
VarargsDemo demo = new VarargsDemo();
// 可变参数的多种调用方式
System.out.println(demo.sum()); // 0 个参数,结果:0
System.out.println(demo.sum(1)); // 1 个参数,结果:1
System.out.println(demo.sum(1, 2, 3)); // 3 个参数,结果:6
System.out.println(demo.sum(1, 2, 3, 4, 5)); // 5 个参数,结果:15
// 也可以直接传入数组
int[] nums = {1, 2, 3, 4, 5};
System.out.println(demo.sum(nums)); // 传入数组,结果:15
}
}
```
```drawio
```
### **2.6 参数传递机制**
```drawio
```
```java
public class ParameterPassDemo {
public static void main(String[] args) {
// ═══════════════════════════════════════════════════════════════
// 1. 基本类型传递
// ═══════════════════════════════════════════════════════════════
int num = 10;
changeValue(num);
System.out.println("num = " + num); // 还是 10,未改变
// ═══════════════════════════════════════════════════════════════
// 2. 引用类型传递 - 修改对象内容
// ═══════════════════════════════════════════════════════════════
int[] arr = {1, 2, 3};
changeArray(arr);
System.out.println("arr[0] = " + arr[0]); // 变成 100
// ═══════════════════════════════════════════════════════════════
// 3. 引用类型传递 - 试图改变引用指向
// ═══════════════════════════════════════════════════════════════
int[] arr2 = {1, 2, 3};
changeReference(arr2);
System.out.println("arr2[0] = " + arr2[0]); // 还是 1,引用未改变
// ═══════════════════════════════════════════════════════════════
// 4. String 的特殊性
// ═══════════════════════════════════════════════════════════════
String str = "Hello";
changeString(str);
System.out.println("str = " + str); // 还是 "Hello"
}
// 基本类型:修改的是副本
public static void changeValue(int n) {
n = 100; // 只修改了副本
}
// 引用类型:可以通过引用修改对象内容
public static void changeArray(int[] array) {
array[0] = 100; // 修改了原对象的内容
}
// 引用类型:不能改变原引用的指向
public static void changeReference(int[] array) {
array = new int[]{100, 200, 300}; // 只改变了副本的指向
}
// String 是不可变的
public static void changeString(String s) {
s = "World"; // 创建了新对象,原引用不变
}
}
```
```drawio
```
### **2.7 递归方法**
```drawio
```
```java
public class RecursionDemo {
// ═══════════════════════════════════════════════════════════════════
// 1. 阶乘:n! = n × (n-1)!
// ═══════════════════════════════════════════════════════════════════
public static long factorial(int n) {
// 递归出口
if (n <= 1) {
return 1;
}
// 递归体
return n * factorial(n - 1);
}
// ═══════════════════════════════════════════════════════════════════
// 2. 斐波那契数列:F(n) = F(n-1) + F(n-2)
// ═══════════════════════════════════════════════════════════════════
public static long fibonacci(int n) {
// 递归出口
if (n <= 1) {
return n;
}
// 递归体(效率较低,有重复计算)
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 优化版:使用记忆化
public static long fibonacciOptimized(int n, long[] memo) {
if (n <= 1) {
return n;
}
if (memo[n] != 0) {
return memo[n]; // 已计算过,直接返回
}
memo[n] = fibonacciOptimized(n - 1, memo) + fibonacciOptimized(n - 2, memo);
return memo[n];
}
// ═══════════════════════════════════════════════════════════════════
// 3. 二分查找
// ═══════════════════════════════════════════════════════════════════
public static int binarySearch(int[] arr, int target, int left, int right) {
// 递归出口
if (left > right) {
return -1; // 未找到
}
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid; // 找到了
} else if (arr[mid] > target) {
return binarySearch(arr, target, left, mid - 1);
} else {
return binarySearch(arr, target, mid + 1, right);
}
}
public static void main(String[] args) {
System.out.println("5! = " + factorial(5)); // 120
System.out.println("fib(10) = " + fibonacci(10)); // 55
int[] arr = {1, 3, 5, 7, 9, 11, 13};
System.out.println("index of 7: " + binarySearch(arr, 7, 0, arr.length - 1)); // 3
}
}
```
```drawio
```
---
## 三、构造方法
### **3.1 构造方法基础**
```drawio
```
```java
public class Person {
private String name;
private int age;
// ═══════════════════════════════════════════════════════════════════
// 无参构造方法
// ═══════════════════════════════════════════════════════════════════
public Person() {
this.name = "Unknown";
this.age = 0;
System.out.println("无参构造方法被调用");
}
// ═══════════════════════════════════════════════════════════════════
// 有参构造方法
// ═══════════════════════════════════════════════════════════════════
public Person(String name) {
this.name = name;
this.age = 0;
System.out.println("一个参数的构造方法被调用");
}
// ═══════════════════════════════════════════════════════════════════
// 全参构造方法
// ═══════════════════════════════════════════════════════════════════
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("两个参数的构造方法被调用");
}
// ═══════════════════════════════════════════════════════════════════
// 构造方法调用另一个构造方法(this())
// ═══════════════════════════════════════════════════════════════════
public Person(String name, int age, String ignored) {
this(name, age); // 调用两个参数的构造方法,必须在第一行
// 其他初始化代码...
}
public static void main(String[] args) {
Person p1 = new Person(); // 无参构造
Person p2 = new Person("Tom"); // 一个参数
Person p3 = new Person("Jerry", 20); // 两个参数
}
}
```
### **3.2 构造方法与继承**
```drawio
```
```java
class Parent {
private String name;
static {
System.out.println("1. 父类静态代码块");
}
{
System.out.println("3. 父类实例代码块");
}
public Parent() {
System.out.println("4. 父类无参构造方法");
}
public Parent(String name) {
this.name = name;
System.out.println("4. 父类有参构造方法");
}
}
class Child extends Parent {
private int age;
static {
System.out.println("2. 子类静态代码块");
}
{
System.out.println("5. 子类实例代码块");
}
public Child() {
// 隐式调用 super();
System.out.println("6. 子类无参构造方法");
}
public Child(String name, int age) {
super(name); // 显式调用父类有参构造方法
this.age = age;
System.out.println("6. 子类有参构造方法");
}
}
// 运行 new Child() 输出:
// 1. 父类静态代码块
// 2. 子类静态代码块
// 3. 父类实例代码块
// 4. 父类无参构造方法
// 5. 子类实例代码块
// 6. 子类无参构造方法
```
---
## 四、this 与 super 关键字
```drawio
```
```java
class Animal {
protected String name = "Animal";
public void eat() {
System.out.println("Animal eating");
}
}
class Dog extends Animal {
private String name = "Dog"; // 同名成员变量
public void eat() {
System.out.println("Dog eating");
}
public void demo() {
// ═══════════════════════════════════════════════════════════════
// this 的使用
// ═══════════════════════════════════════════════════════════════
System.out.println(this.name); // "Dog" - 当前类的 name
this.eat(); // "Dog eating" - 当前类的方法
// ═══════════════════════════════════════════════════════════════
// super 的使用
// ═══════════════════════════════════════════════════════════════
System.out.println(super.name); // "Animal" - 父类的 name
super.eat(); // "Animal eating" - 父类的方法
}
public void showThis() {
// this 可以作为参数传递,表示当前对象
printObject(this);
}
public void printObject(Dog d) {
System.out.println(d.name);
}
}
```
---
## 五、方法调用的内存过程
```drawio
```
```drawio
```
---
## 六、常见面试题
```drawio
```
```java
// 经典面试题:下面代码输出什么?
public class Test {
public static void main(String[] args) {
String str = "hello";
change(str);
System.out.println(str); // 输出:hello
StringBuilder sb = new StringBuilder("hello");
change(sb);
System.out.println(sb); // 输出:helloworld
}
public static void change(String s) {
s = "world"; // 新对象,不影响原引用
}
public static void change(StringBuilder sb) {
sb.append("world"); // 修改原对象内容
}
}
```