Java方法专题 - 动手动脑问题与实验总结

一、随机数生成相关实验

动手动脑1:纯随机数发生器实现

问题要求:
编写一个方法,使用线性同余算法生成指定数目(比如1000个)的随机整数。

算法参数:

  • Modulus = 2³¹ - 1 = int.MaxValue
  • Multiplier = 7⁵ = 16807
  • C = 0

实现代码:

public class LinearCongruentialGenerator {
    private static final long MODULUS = 2147483647L; // 2^31 - 1
    private static final long MULTIPLIER = 16807L;
    private long seed;
    
    public LinearCongruentialGenerator(long seed) {
        this.seed = seed;
    }
    
    public int nextInt() {
        seed = (MULTIPLIER * seed) % MODULUS;
        return (int) seed;
    }
    
    // 生成指定数量的随机整数
    public static int[] generateRandomNumbers(int count, long seed) {
        LinearCongruentialGenerator generator = new LinearCongruentialGenerator(seed);
        int[] numbers = new int[count];
        for (int i = 0; i < count; i++) {
            numbers[i] = generator.nextInt();
        }
        return numbers;
    }
}

学习要点:

  • 理解伪随机数生成原理
  • 掌握线性同余算法的实现
  • 学会建立个人代码仓库,积累实用工具类

二、可变参数方法

动手动脑2:可变参数方法的特点

示例代码分析:

public class VariableArgumentsTest {
    public static double max(double... values) {
        double largest = Double.MIN_VALUE;
        for (double v : values) {
            if (v > largest) largest = v;
        }
        return largest;
    }
    
    public static void main(String[] args) {
        System.out.println("Max: " + max(1, 11, 300, 2, 3));
    }
}

可变参数特点总结:

  1. 位置要求:只能出现在方法参数列表的最后
  2. 语法格式:"..."位于变量类型和变量名之间,前后有无空格均可
  3. 实现机制:编译器为可变参数隐含创建数组
  4. 访问方式:在方法体中以数组形式访问可变参数

三、方法重载

动手动脑3:方法重载特性分析

示例代码:

public class MethodOverload {
    public static void main(String[] args) {
        System.out.println("The square of integer 7 is " + square(7));
        System.out.println("The square of double 7.5 is " + square(7.5));
    }
    
    public static int square(int x) {
        return x * x;
    }
    
    public static double square(double y) {
        return y * y;
    }
}

方法重载要点:

  1. 必要条件

    • 方法名相同
    • 参数类型不同,或参数个数不同,或参数类型的顺序不同
  2. 非判断条件:方法的返回值类型

  3. 实践练习

    • 查看JDK中System.out.println()方法的重载形式
    • 发现println方法有多个重载版本,分别处理不同数据类型

四、递归与递推

动手动脑4:n!的递归与递推实现对比

递归实现:

public class RecursionExample {
    // 递归方式计算阶乘
    public static long factorialRecursive(int n) {
        if (n == 0 || n == 1) {
            return 1; // 递归结束条件
        }
        return n * factorialRecursive(n - 1); // 自己调用自己
    }
}

递推实现:

public class IterationExample {
    // 递推方式计算阶乘
    public static long factorialIterative(int n) {
        long result = 1;
        for (int i = 1; i <= n; i++) {
            result *= i; // 从前到后逐步计算
        }
        return result;
    }
}

递归编程模式总结:

  1. 递归头:函数开头必须判断递归结束条件
  2. 递归体:至少有一句"自己调用自己"
  3. 控制变量:必须有控制递归终结的参数变量

递归 vs 递推对比:

特性 递归 递推
执行方向 由后至前再回来 从前到后
实现方式 函数自我调用 循环语句
内存使用 栈空间消耗大 栈空间消耗小
代码可读性 更符合数学思维 更直观易懂

五、大数字与浮点数处理

动手动脑5:大整数阶乘计算

问题现象:
使用int或long类型计算较大数的阶乘时会出现负数结果

问题根源:

  • int类型:32位,最大值2,147,483,647
  • long类型:64位,最大值9,223,372,036,854,775,807
  • 数值超出范围时发生二进制截断

解决方案:使用BigInteger类

import java.math.BigInteger;

public class BigNumberExample {
    public static BigInteger calculateBigFactorial(int n) {
        if (n == 0 || n == 1) {
            return BigInteger.valueOf(1);
        }
        return BigInteger.valueOf(n).multiply(calculateBigFactorial(n - 1));
    }
}

动手动脑6:浮点数精度比较

问题代码:

double i = 0.0001;
double j = 0.00010000000000000001;
System.out.println(i == j); // 输出:true

正确比较方法:

// 比较两个浮点数的差值是否在允许范围内
public static boolean doubleEquals(double a, double b, double epsilon) {
    return Math.abs(a - b) < epsilon;
}

// 使用示例
if (doubleEquals(i, j, 1e-10)) {
    System.out.println("在精度范围内相等");
} else {
    System.out.println("不相等");
}

六、课后实验项目

实验项目:四则运算题目生成器

阶段1要求:
花二十分钟写一个能自动生成30道小学四则运算题目的"软件"

基础实现思路:

public class ArithmeticGenerator {
    private Random random = new Random();
    
    public void generateQuestions(int count) {
        for (int i = 0; i < count; i++) {
            int num1 = random.nextInt(100);
            int num2 = random.nextInt(100);
            char operator = getRandomOperator();
            System.out.println((i+1) + ". " + num1 + " " + operator + " " + num2 + " = ");
        }
    }
    
    private char getRandomOperator() {
        char[] operators = {'+', '-', '×', '÷'};
        return operators[random.nextInt(operators.length)];
    }
}

阶段2进阶要求:

  1. 题目质量

    • 避免重复题目
    • 减法不允许出现负数
    • 乘法结果不允许出现四位数
    • 除法必须整除不允许出现小数
  2. 功能扩展

    • 实现在线实时答题
    • 统计显示错题数和正确率
    • 增加倒计时功能

方法设计建议:

public class AdvancedArithmeticTest {
    // 检查题目是否重复
    public static boolean isDuplicate(String question, Set<String> existingQuestions) {
        return existingQuestions.contains(question);
    }
    
    // 验证减法结果非负
    public static boolean isValidSubtraction(int a, int b) {
        return a >= b;
    }
    
    // 验证乘法结果不超过四位数
    public static boolean isValidMultiplication(int a, int b) {
        return a * b < 10000;
    }
    
    // 验证除法可以整除
    public static boolean isValidDivision(int a, int b) {
        return b != 0 && a % b == 0;
    }
}

七、学习总结与最佳实践

代码仓库建设

  1. 分类整理:按功能模块分类存储代码片段
  2. 注释完善:为每个方法添加详细的使用说明
  3. 测试用例:为重要方法编写测试代码
  4. 文档配套:建立配套的使用文档和示例

开发效率提升

  1. 避免重复造轮子:充分利用已有代码资源
  2. 方法设计原则:单一职责、参数验证、异常处理
  3. 递归使用场景:树形结构、分治算法、动态规划
  4. 大数处理:金融计算、科学运算等场景使用BigDecimal/BigInteger

问题解决思路

  1. 理解问题本质:如整数溢出、浮点精度等根本原因
  2. 选择合适的工具:根据需求选择递归或递推实现
  3. 边界条件处理:特别注意递归结束条件和数值边界
  4. 性能与可读性平衡:在保证正确性的前提下优化代码

附录:完整代码示例

完整的四则运算题目生成器

import java.util.*;

public class CompleteArithmeticGenerator {
    private Random random = new Random();
    private Set<String> generatedQuestions = new HashSet<>();
    
    public void generateAdvancedQuestions(int count) {
        generatedQuestions.clear();
        for (int i = 0; i < count; i++) {
            String question = generateValidQuestion();
            System.out.println((i+1) + ". " + question);
        }
    }
    
    private String generateValidQuestion() {
        String question;
        do {
            int num1 = random.nextInt(100) + 1;
            int num2 = random.nextInt(100) + 1;
            char operator = getRandomOperator();
            
            // 根据运算符进行验证
            switch (operator) {
                case '-':
                    if (!isValidSubtraction(num1, num2)) {
                        // 确保被减数大于等于减数
                        int temp = num1;
                        num1 = Math.max(num1, num2);
                        num2 = Math.min(temp, num2);
                    }
                    break;
                case '×':
                    if (!isValidMultiplication(num1, num2)) {
                        // 调整数值使乘积不超过四位数
                        num1 = random.nextInt(100) + 1;
                        num2 = random.nextInt(100) + 1;
                        continue;
                    }
                    break;
                case '÷':
                    if (!isValidDivision(num1, num2)) {
                        // 调整数值使能够整除
                        num2 = random.nextInt(20) + 1;
                        num1 = num2 * (random.nextInt(50) + 1);
                    }
                    break;
            }
            
            question = num1 + " " + operator + " " + num2 + " = ";
        } while (generatedQuestions.contains(question));
        
        generatedQuestions.add(question);
        return question;
    }
    
    private char getRandomOperator() {
        char[] operators = {'+', '-', '×', '÷'};
        return operators[random.nextInt(operators.length)];
    }
    
    private boolean isValidSubtraction(int a, int b) {
        return a >= b;
    }
    
    private boolean isValidMultiplication(int a, int b) {
        return a * b < 10000;
    }
    
    private boolean isValidDivision(int a, int b) {
        return b != 0 && a % b == 0;
    }
    
    public static void main(String[] args) {
        CompleteArithmeticGenerator generator = new CompleteArithmeticGenerator();
        generator.generateAdvancedQuestions(30);
    }
}
posted @ 2025-10-08 16:33  Y仙森  阅读(16)  评论(0)    收藏  举报