方法进阶

本课深入学习方法的高级特性,包括递归、静态方法和方法引用。

递归

递归是方法调用自身的编程技巧。

递归三要素

要素 说明
基准条件 递归终止的条件
递归调用 方法调用自身
问题缩小 每次递归问题规模减小

示例:计算阶乘

JAVA
public class Factorial {
    public static long factorial(int n) {
        // 基准条件
        if (n <= 1) {
            return 1;
        }
        // 递归调用
        return n * factorial(n - 1);
    }
    
    public static void main(String[] args) {
        System.out.println("5! = " + factorial(5));  // 120
        System.out.println("10! = " + factorial(10)); // 3628800
    }
}
▶ 试一试

递归过程

TEXT
factorial(5)
  = 5 * factorial(4)
  = 5 * 4 * factorial(3)
  = 5 * 4 * 3 * factorial(2)
  = 5 * 4 * 3 * 2 * factorial(1)
  = 5 * 4 * 3 * 2 * 1
  = 120

示例:斐波那契数列

JAVA
public class Fibonacci {
    public static int fibonacci(int n) {
        if (n <= 1) {
            return n;
        }
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
    
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.print(fibonacci(i) + " ");
        }
        // 输出:0 1 1 2 3 5 8 13 21 34
    }
}
▶ 试一试
⚠️ 注意: 简单递归效率低,可以用记忆化优化。对于斐波那契数列,迭代方式更高效。

示例:递归遍历目录

JAVA
import java.io.File;

public class ListFiles {
    public static void listFiles(File dir, String indent) {
        File[] files = dir.listFiles();
        if (files == null) return;
        
        for (File file : files) {
            System.out.println(indent + file.getName());
            if (file.isDirectory()) {
                listFiles(file, indent + "  ");
            }
        }
    }
    
    public static void main(String[] args) {
        File dir = new File(".");
        listFiles(dir, "");
    }
}
▶ 试一试

静态方法与实例方法

静态方法

static修饰的方法,属于类,不需要创建对象即可调用。

JAVA
public class MathUtils {
    public static int add(int a, int b) {
        return a + b;
    }
}

// 调用
int sum = MathUtils.add(3, 5);

实例方法

没有static的方法,属于对象,需要创建对象才能调用。

JAVA
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}

// 调用
Calculator calc = new Calculator();
int sum = calc.add(3, 5);

对比

特性 静态方法 实例方法
关键字 static
调用方式 类名.方法() 对象.方法()
访问成员 只能访问静态成员 可以访问所有成员
this关键字 不能使用 可以使用

示例:静态方法与实例方法

JAVA
public class MethodTypeDemo {
    private int count = 0;
    
    // 静态方法
    public static int add(int a, int b) {
        return a + b;
    }
    
    // 实例方法
    public void increment() {
        count++;
    }
    
    public int getCount() {
        return count;
    }
    
    public static void main(String[] args) {
        // 静态方法直接调用
        System.out.println(add(3, 5));  // 8
        
        // 实例方法需要对象
        MethodTypeDemo demo = new MethodTypeDemo();
        demo.increment();
        demo.increment();
        System.out.println(demo.getCount());  // 2
    }
}
▶ 试一试

工具类设计

工具类通常只包含静态方法,不需要创建对象。

示例:字符串工具类

JAVA
public class StringUtils {
    // 判断是否为空
    public static boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }
    
    // 判断是否为空白
    public static boolean isBlank(String str) {
        return str == null || str.trim().isEmpty();
    }
    
    // 反转字符串
    public static String reverse(String str) {
        if (str == null) return null;
        return new StringBuilder(str).reverse().toString();
    }
    
    // 首字母大写
    public static String capitalize(String str) {
        if (isEmpty(str)) return str;
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
    
    public static void main(String[] args) {
        System.out.println(isEmpty(""));      // true
        System.out.println(isEmpty("hello")); // false
        System.out.println(reverse("hello")); // olleh
        System.out.println(capitalize("hello")); // Hello
    }
}
▶ 试一试

方法引用

Java 8引入方法引用,是Lambda的简写形式。

四种方法引用

类型 语法 示例
静态方法 类名::静态方法 Math::abs
实例方法 对象::实例方法 System.out::println
特定类的实例方法 类名::实例方法 String::length
构造方法 类名::new ArrayList::new

示例:方法引用

JAVA
import java.util.Arrays;
import java.util.List;

public class MethodRefDemo {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
        
        // Lambda表达式
        names.forEach(name -> System.out.println(name));
        
        // 方法引用(更简洁)
        names.forEach(System.out::println);
        
        // 静态方法引用
        List<Integer> numbers = Arrays.asList(-3, -1, 0, 2, 5);
        numbers.stream()
               .map(Math::abs)
               .forEach(System.out::println);
        // 输出:3 1 0 2 5
    }
}
▶ 试一试

示例:构造方法引用

JAVA
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

public class ConstructorRefDemo {
    public static void main(String[] args) {
        // Lambda表达式
        Supplier<List<String>> listFactory = () -> new ArrayList<>();
        
        // 构造方法引用
        Supplier<List<String>> listFactory2 = ArrayList::new;
        
        List<String> list = listFactory2.get();
        list.add("Hello");
        System.out.println(list);  // [Hello]
    }
}
▶ 试一试

递归优化

尾递归优化

尾递归是指递归调用是函数的最后一个操作。

JAVA
// 普通递归(不是尾递归)
public static long factorial(int n) {
    if (n <= 1) return 1;
    return n * factorial(n - 1);  // 递归后还要乘n
}

// 尾递归版本
public static long factorialTail(int n, long acc) {
    if (n <= 1) return acc;
    return factorialTail(n - 1, n * acc);  // 递归是最后一步
}

// 调用
long result = factorialTail(5, 1);
💡 注意: Java编译器不自动优化尾递归,但理解这个概念对学习其他语言有帮助。

记忆化递归

用缓存存储已计算的结果,避免重复计算。

JAVA
import java.util.HashMap;
import java.util.Map;

public class MemoFibonacci {
    private static Map<Integer, Long> cache = new HashMap<>();
    
    public static long fibonacci(int n) {
        if (n <= 1) return n;
        
        // 检查缓存
        if (cache.containsKey(n)) {
            return cache.get(n);
        }
        
        // 计算并缓存
        long result = fibonacci(n - 1) + fibonacci(n - 2);
        cache.put(n, result);
        return result;
    }
    
    public static void main(String[] args) {
        System.out.println(fibonacci(50));  // 12586269025
    }
}

❓ 常见问题

Q 递归和循环怎么选?
A 简单问题用循环更高效。递归适合树形结构、分治算法等天然递归的问题。
Q 什么时候用静态方法?
A 工具方法、不需要访问对象状态的方法用静态。需要访问对象状态用实例方法。
Q 方法引用和Lambda有什么区别?
A 方法引用是Lambda的简写,更简洁。但不是所有Lambda都能用方法引用替代。

📖 小节

📝 作业

  1. 递归练习: 用递归计算1到n的和
  2. 递归练习: 用递归反转字符串
  3. 工具类: 编写一个数学工具类,包含求最大值、最小值、平均值等方法

下一课

下一课我们将学习 String类,了解字符串的常用操作。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏