Java课程动脑与课堂实验题目整理
Java 课程动手动脑与课堂实验题目整理
一、动手动脑:线性同余随机数生成器
1.1 题目原文
编写一个方法,使用以下算法生成指定数目(比如 1000 个)的随机整数。
其中使用的算法为线性同余法,数学公式如下:
x(n+1) = (a × x(n) + c) mod m
1.2 算法参数
- Modulus(模)m = 2^31 - 1 = 2147483647,即 int.MaxValue
- Multiplier(乘数)a = 7^5 = 16807
- Increment(增量)c = 0
- Seed(种子):x0,为随机数序列的初始值
- 说明:该随机数发生器在输出过 2^31 - 2 个数之后,才可能出现重复
1.3 算法原理
线性同余发生器(Linear Congruential Generator,LCG)是经典的伪随机数生成算法。每次计算时,将当前的随机数 x(n) 代入公式 x(n+1) = (a × x(n) + c) mod m,得到下一个随机数 x(n+1),如此反复迭代即可产生一串随机整数。本例中增量 c = 0,因此也称为“乘同余法”,是 LCG 的一种特例。
由于每次结果都对模 m 取余,生成的数值范围始终落在 [0, m-1] 之间。选择 m = 2^31 - 1、a = 16807 是一组经过验证的经典参数,能够在较长的周期内保证序列的随机性与均匀性。种子 x0 决定整个序列的起点,不同种子会得到不同的随机数序列。
1.4 参考代码(Java)
import java.util.Scanner;
/**
* 线性同余随机数生成器
* 公式:x(n+1) = (a * x(n) + c) mod m
* 参数:m = 2^31 - 1 = 2147483647(int.MaxValue)
* a = 7^5 = 16807,c = 0
*/
public class LinearCongruentialRandom {
// 模 m = 2^31 - 1
private static final long MODULUS = (1L << 31) - 1;
// 乘数 a = 7^5
private static final long MULTIPLIER = 16807;
// 增量 c = 0
private static final long INCREMENT = 0;
private long seed; // 当前值(由种子开始)
/** 构造方法:以指定种子初始化 */
public LinearCongruentialRandom(long seed) {
this.seed = seed;
}
/** 生成下一个随机整数 */
public long next() {
// 将当前值代入公式,得到下一个随机数
seed = (MULTIPLIER * seed + INCREMENT) % MODULUS;
return seed;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("请输入要生成的随机数个数:");
int count = in.nextInt();
// 以种子 1 开始生成
LinearCongruentialRandom random = new LinearCongruentialRandom(1);
for (int i = 1; i <= count; i++) {
System.out.println(i + " : " + random.next());
}
in.close();
}
}
1.5 运行示例
请输入要生成的随机数个数:5
1 : 16807
2 : 282475249
3 : 1622650073
4 : 984943658
5 : 1144108930
1.6 学习指导
在实际开发中,生成随机数是一个比较实用的功能,可以将实现它的相关代码整理并收集起来。在学习过程中应该注意积累和整理各种有用的代码,分门别类地整理好,建立自己的代码仓库,这样一来,在编程时就能快速查找到相应的代码,从而有效地提升自己的开发效率。
使用自己收集整理的资料库,通常比使用搜索引擎查找资料要高效得多。
二、课堂测试一(阶段1):小学四则运算题目生成器
2.1 背景故事(疑问看故事)
一家软件公司的程序员二柱,小孩上了小学二年级,老师让家长每天出 30 道四则运算题目给小学生做。
二柱立马就想到写一个小程序来做这件事。这个事情可以用很多语言或者工具来实现:Excel、C/C++、C#、VB、Unix Shell、Emacs、Powershell/Vbscript、Javascript、Perl、Python……
请大家估计写好这个程序需要的时间。我想程序员用自己最擅长的工具,一支烟的功夫就搞定了。
2.2 题目原文
阶段1:像二柱子那样,花二十分钟写一个能自动生成 30 道小学四则运算题目的“软件”。
2.3 需求要点
- 一次性输出 30 道四则运算算式(加、减、乘、除)
- 数字范围适合小学二年级水平(这里取 1~100 的整数)
- 在控制台打印题目即可
2.4 参考代码(Java)
import java.util.Random;
/**
* 小学四则运算题目生成器(阶段1)
* 自动生成 30 道加减乘除算式
*/
public class ArithmeticGenerator {
public static void main(String[] args) {
Random random = new Random();
for (int i = 0; i < 30; i++) {
// 随机生成 1~100 的两个整数
int a = random.nextInt(100) + 1;
int b = random.nextInt(100) + 1;
// 从 + - * / 中随机选一个运算符
char[] ops = {'+', '-', '*', '/'};
char op = ops[random.nextInt(ops.length)];
// 输出题目
System.out.println("(" + (i + 1) + ") " + a + " " + op + " " + b + " = ");
}
}
}
2.5 运行示例
(1) 56 + 23 =
(2) 78 - 45 =
(3) 12 * 8 =
(4) 90 / 6 =
(5) 34 + 17 =
…… (共 30 道)
三、课堂测试二(阶段2):四则运算增强版
3.1 题目原文
阶段2:(1)要求题目避免重复,减法不允许出现负数。
3.2 需求要点(阶段1 + 阶段2 约束)
- 一共生成 30 道题目,题目不能重复
- 减法运算不允许出现负数(被减数 ≥ 减数)
- 除法运算结果为整数(整除),除数不为 0
3.3 参考代码(Java)
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
/**
* 小学四则运算题目生成器(阶段2·增强版)
* 约束:题目不重复;减法不出负数;除法整除且除数不为0
*/
public class EnhancedArithmeticGenerator {
public static void main(String[] args) {
Random random = new Random();
Set<String> used = new HashSet<>(); // 记录已生成的题目,避免重复
int count = 0; // 已生成题目数
while (count < 30) {
int a = random.nextInt(100) + 1; // 1~100
int b = random.nextInt(100) + 1; // 1~100
char[] ops = {'+', '-', '*', '/'};
char op = ops[random.nextInt(ops.length)];
// 约束1:减法不允许出现负数 -> 保证 a >= b
if (op == '-') {
if (a < b) {
int t = a; a = b; b = t; // 交换,使 a >= b
}
}
// 约束2:除法要整除、除数不为0 -> 将 b 调整为 a 的因子
if (op == '/') {
if (b == 0) b = 1;
a = (a / b) * b; // 使 a 是 b 的整数倍
if (b == 0) b = 1;
}
String question = a + " " + op + " " + b + " = ";
// 约束3:题目不重复
if (used.contains(question)) {
continue; // 已出现过,重新生成
}
used.add(question);
System.out.println("(" + (count + 1) + ") " + question);
count++;
}
}
}
3.4 运行示例
(1) 56 + 23 =
(2) 78 - 45 =
(3) 12 * 8 =
(4) 90 / 6 =
(5) 34 - 34 =
…… (共 30 道,且均不重复)
四、练习:方法重载——查看 System.out.println()
4.1 知识点:方法重载的要点
在 Java 中,满足以下条件的两个或多个方法构成“重载(overload)”关系:
- (1)方法名相同;
- (2)参数类型不同,参数个数不同,或者是参数类型的顺序不同。
注意:方法的返回值不作为方法重载的判断条件。也就是说,即使返回值不同,只要方法名和参数列表相同,也不能构成重载。
4.2 练习原文
查看一下 JDK 中 System.out.println() 方法,你发现了什么?
4.3 观察与结论
System.out.println() 是 Java 中最常用的输出方法之一。通过查看 JDK 源码可以发现,System.out 是一个 PrintStream 类型的对象,而 PrintStream 类中定义了大量名为 println 的方法,它们方法名完全相同,但参数列表各不相同,例如:println()、println(char)、println(int)、println(long)、println(float)、println(double)、println(boolean)、println(char[])、println(String)、println(Object) 等。
这正是“方法重载”的典型体现:方法名统一为 println,通过不同的参数类型(String、int、double、boolean、Object……)来自动匹配并输出对应的内容。我们在调用 System.out.println() 时传入不同类型的参数,编译器会自动选择参数匹配的重载版本,这正是方法重载带给编程的便利。
4.4 参考代码(Java)
/**
* 演示:自定义一个支持多种参数类型的 println 方法(模拟方法重载)
*/
public class PrintlnDemo {
// 重载:方法名相同,参数类型不同
public static void println(int x) {
System.out.println("整数: " + x);
}
public static void println(double x) {
System.out.println("小数: " + x);
}
public static void println(String s) {
System.out.println("字符串: " + s);
}
public static void println(boolean b) {
System.out.println("布尔: " + b);
}
public static void println(Object o) {
System.out.println("对象: " + o);
}
public static void main(String[] args) {
// 编译器按参数类型自动选择对应的重载方法
println(10); // int
println(3.14); // double
println("你好,Java"); // String
println(true); // boolean
println(new PrintlnDemo()); // Object
}
}
4.5 运行示例
整数: 10
小数: 3.14
字符串: 你好,Java
布尔: true
对象: PrintlnDemo@15db9742
浙公网安备 33010602011771号