这是一份为你精心定制的Java 期末模拟试卷

出题策略: 这份模拟卷严格参照你提供的真题结构、难度分布和考点覆盖范围进行编写。通过“同构题”(考点相同但题目形式不同)和“进阶题”(考点相关但略有延伸)的组合,帮助你检测复习是否存在死角。


Java 期末模拟仿真卷

考试时间: 120分钟
满分: 100分


第一部分:简答与程序分析题 (每题 5 分,共 55 分)

1. 分析下列程序,并简述 String 对象的不可变性(Immutability),并给出运行结果。

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class StringTest {
public static void change(String s, char[] c) {
s = "changed";
c[0] = 'g';
}

public static void main(String[] args) {
String str = "good";
char[] ch = { 'a', 'b', 'c' };
change(str, ch);
System.out.print(str + " and ");
System.out.print(ch);
}
}

2. 简述 Java 中 static 关键字的作用。请分别说明 static 修饰成员变量、成员方法以及静态代码块时的特点和执行时机。

3. 在处理大量无需重复且不要求顺序的数据时,你会选择 Java 集合框架中的 HashSet 还是 TreeSet?请从底层数据结构(Hash表 vs 红黑树)和性能角度(时间复杂度)进行论述。

4. 简述 Java 中四种访问权限修饰符(private, default/friendly, protected, public)的作用范围区别。

5. 简述线程生命周期中的 sleep() 方法和 wait() 方法的区别。如果线程类已经实现了 Runnable 接口,是否还能通过继承 Thread 类的方式创建线程?为什么?

6. 分析下列程序,指出多态在其中的体现。请问 output 方法中的 b.show(b) 调用的是哪个类的方法?并写出最终的输出结果。

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class A {
public String show(D obj) { return ("A and D"); }
public String show(A obj) { return ("A and A"); }
}
class B extends A {
public String show(B obj) { return ("B and B"); }
public String show(A obj) { return ("B and A"); }
}
class C extends B {}
class D extends B {}

public class PolyTest {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); // ①
System.out.println(a2.show(b)); // ②
}
}

7. 简述 HashtableHashMap 的区别(提示:从线程安全、null 值支持、效率三个方面回答)。

8. 分析下列程序关于 try-catch-finally 块中 return 语句的执行顺序,并写出运行结果。

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ReturnTest {
public static int test() {
int x = 1;
try {
return x;
} finally {
++x;
System.out.print("finally run, ");
}
}
public static void main(String[] args) {
System.out.println("result=" + test());
}
}

9. 简述 Java 中的受检异常(Checked Exception)和运行时异常(Runtime Exception)的区别,并各举一个例子。

10. 分析下列程序的初始化顺序(静态代码块 vs 构造代码块 vs 构造方法),并写出运行结果。

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
class Base {
static { System.out.print("Base Static, "); }
public Base() { System.out.print("Base Const, "); }
}
class Sub extends Base {
static { System.out.print("Sub Static, "); }
{ System.out.print("Sub Block, "); }
public Sub() { System.out.print("Sub Const"); }

public static void main(String[] args) {
new Sub();
}
}

11. 下列代码试图实现一个简单的银行账户取款操作。在多线程环境下,该代码是否存在线程安全问题?如果存在,请指出问题所在,并使用 synchronized 关键字给出一种修改方案(可以修饰方法或代码块)。

Java

1
2
3
4
5
6
7
8
9
class Account {
private int balance = 1000;
public void withdraw(int amount) {
if (balance >= amount) {
try { Thread.sleep(10); } catch (Exception e) {} // 模拟网络延迟
balance = balance - amount;
}
}
}

第二部分:编程题 (共 45 分)

1. (15分) 集合与排序
定义一个学生类 Student,满足以下要求:

  • (1) 包含成员变量:姓名 name (String),成绩 score (int)。
  • (2) 提供带参构造方法初始化姓名和成绩。
  • (3) 覆写 toString() 方法,返回格式为 “Name: xxx, Score: xxx”。
  • (4) 在 main 方法中,创建 4 个学生对象存入 ArrayList 中。
  • (5) 核心要求:使用 Collections.sort 方法对学生按照成绩从高到低进行排序。如果成绩相同,则按照姓名的字典序(字母顺序)排列。最后遍历集合打印排序后的结果。
    • 提示:可以使用 Comparator 接口或让 Student 类实现 Comparable 接口。

2. (15分) 接口与多态应用
为了模拟计算机连接不同 USB 设备的功能,请设计以下类和接口:

  • (1) 定义一个接口 USB,包含两个抽象方法:void open() (开启设备) 和 void close() (关闭设备)。
  • (2) 定义两个实现类 Mouse (鼠标) 和 Keyboard (键盘),它们都实现 USB 接口。
    • Mouseopen 打印 “鼠标连接”,close 打印 “鼠标断开”。
    • Keyboardopen 打印 “键盘连接”,close 打印 “键盘断开”。
  • (3) 定义一个类 Laptop (笔记本电脑),包含一个方法 public void useUSB(USB usb)
    • 该方法首先调用传入设备的 open() 方法。
    • 进阶考点:使用 instanceof 判断传入的设备类型:如果是 Mouse,额外打印 “进行点击操作”;如果是 Keyboard,额外打印 “进行打字操作”。
    • 最后调用设备的 close() 方法。
  • (4) 编写 main 方法,实例化 Laptop,并分别测试插入 MouseKeyboard 对象。

3. (15分) IO 流与文件处理
编写一个 Java 程序实现简单的文件内容拷贝与处理功能:

  • (1) 程序需要读取当前目录下名为 source.txt 的文本文件(假设文件已存在)。
  • (2) 使用字符流(如 FileReader/BufferedReader)逐行读取文件内容。
  • (3) 将读取到的每一行内容转换成大写字母 (UpperCase)。
  • (4) 将转换后的内容写入到当前目录下的 dest.txt 文件中(使用 FileWriter/PrintWriter)。
  • (5) 核心要求:必须使用标准的 try-catch-finally 结构(或 try-with-resources)来处理 IO 异常,并确保在 finally 块中正确关闭输入流和输出流,防止资源泄露。

💡 模拟卷考点对标分析 (为什么这么出题?)

题目 真题考点 模拟卷考点 差异化/复习目的
简 1 值传递 vs 引用传递 String 不可变性 + 数组引用传递 String 是特殊的引用类型,是面试和考试的常客。
简 2 抽象类 vs 接口 static 关键字详解 static 是 Java 基础中仅次于 OOP 的核心概念。
简 3 ArrayList vs LinkedList HashSet vs TreeSet 考察对 Set 体系及哈希/树结构的理解。
简 4 final/finally 访问修饰符 (public/private…) 考察封装性基础,必须死记硬背的知识点。
简 5 线程定义方式 sleep() vs wait() 线程状态控制是多线程考题的另一面。
简 6 重载 vs 覆写 复杂多态/动态绑定 难度升级,考察引用类型与实际对象类型不一致时的调用规则。
简 7 Map 接口特点 Hashtable vs HashMap 经典的“线程安全 vs 性能”对比。
简 8 String vs StringBuilder try-catch-return 执行顺序 考察 finally 的强制执行性,这是一个经典陷阱。
简 9 自定义异常 异常分类 (Checked vs Runtime) 考察对 Java 异常体系结构的宏观理解。
简 10 super/this 构造 类加载与对象初始化顺序 更加深入考察代码块的执行时机(考研/面试高频)。
简 11 线程同步问题 银行取款线程安全问题 场景变了,但核心考点依然是“读-改-写”原子性。
编 1 复数类 + 排序 学生类 + 复合排序 增加了“成绩相同按姓名排”的逻辑,考察 Comparator 的灵活运用。
编 2 接口 (体积计算) 接口 (USB设备) + instanceof 增加了向下转型 (Downcasting) 的考查。
编 3 Socket + IO 文件 IO + 异常处理 将网络编程替换为纯文件操作,强化流的关闭和异常处理规范。

没问题,这是为您单独整理的Java 期末模拟卷参考答案


Java 期末模拟仿真卷 - 参考答案

第一部分:简答与程序分析题答案

1. String 不可变性分析

  • 运行结果: good and gbc
  • 解析:
    • Java 中 String 是不可变对象。change 方法中的 sstr 引用的副本,s = "changed" 只是将副本指向了堆中的新字符串常量,原 str 指向的 “good” 保持不变。
    • 数组是引用类型,cch 指向堆中同一个数组对象,修改 c[0] 会直接改变原数组内容。

2. static 关键字

  • 成员变量: 静态变量(类变量),全类共享一份,随着类的加载而创建,不依赖于对象实例。
  • 成员方法: 静态方法,通过类名直接调用,不能直接访问非静态成员(因为没有 this 指针)。
  • 静态代码块: 在类被 JVM 加载时执行,且只执行一次,通常用于初始化静态资源(如 JDBC 驱动加载)。

3. HashSet vs TreeSet

  • 选择: HashSet
  • 原因:
    • HashSet 底层是哈希表,插入和查找的时间复杂度接近 $O(1)$,效率极高。
    • TreeSet 底层是红黑树,虽然能排序,但时间复杂度为 $O(\log n)$,效率不如 HashSet。
    • 题目明确说明“不要求顺序”,因此追求性能选 HashSet

4. 访问权限修饰符

  • private: 仅本类可见。
  • default (不写): 本类 + 同包可见。
  • protected: 本类 + 同包 + 不同包的子类可见。
  • public: 所有类可见。

5. sleep() vs wait()

  • 区别:
    • sleep()Thread 类的静态方法,让线程暂停执行,不会释放锁
    • wait()Object 类的方法,必须在同步代码块/方法中调用,让线程暂停,会释放锁
  • 能否继承 Thread: 不能。
    • 原因: Java 是单继承机制。如果类已经实现了 Runnable 接口,它通常是为了解决已经继承了其他父类的问题。如果该类已经继承了别的父类,就无法再继承 Thread 类。

6. 多态分析

  • 运行结果:
    • A and A
    • B and A
  • 解析:
    • 引用变量类型决定了编译时能调用哪些方法(只能调用 A 类有的方法)。
    • 实际对象类型决定了运行时执行哪个版本的方法(如果子类覆写了,执行子类的)。
    • a1.show(b):A 类中没有 show(B),只有 show(A)。B 是 A 的子类,所以匹配 show(A)
    • a2.show(b)a2 是 B 的实例。B 类覆写了 show(A)。所以调用 B 类的 show(A) 方法,输出 B and A

7. Hashtable vs HashMap

  • 线程安全: Hashtable 是线程安全的(方法有 synchronized),HashMap 不是。
  • Null 值: Hashtable 的键和值都不允许 null;HashMap 允许一个 null 键和多个 null 值。
  • 效率: HashMap 效率高于 Hashtable(因为没有同步锁的开销)。

8. try-catch-finally 执行顺序

  • 运行结果: finally run, result=1
  • 解析:
    • try 块中的 return x 执行时,会将 x 的值(1)暂存在栈中准备返回。
    • 程序必须先执行 finally 块,此时 x 变为 2。
    • finally 执行完毕后,方法真正返回,返回的是之前暂存的值(1),而不是修改后的 2。

9. 异常类型区别

  • 受检异常 (Checked Exception): 编译器强制要求处理(try-catch 或 throws),通常是外部错误。
    • 例子: IOException, SQLException, ClassNotFoundException
  • 运行时异常 (Runtime Exception): 编译器不强制处理,通常是编程逻辑错误。
    • 例子: NullPointerException, IndexOutOfBoundsException, ArithmeticException

10. 初始化顺序

  • 运行结果: Base Static, Sub Static, Base Const, Sub Block, Sub Const
  • 顺序规则:
    1. 父类静态代码块
    2. 子类静态代码块
    3. 父类构造方法
    4. 子类构造代码块
    5. 子类构造方法

11. 线程安全分析

  • 问题: 存在线程安全问题(竞态条件)。多个线程可能同时通过 if(balance >= amount) 判断,导致余额扣减成负数。
  • 修改方案: 在方法上添加 synchronized 关键字。
    1
    2
    3
    4
    5
    6
    public synchronized void withdraw(int amount) {
    if (balance >= amount) {
    try { Thread.sleep(10); } catch (Exception e) {}
    balance = balance - amount;
    }
    }

第二部分:编程题参考代码

1. 集合与排序 (Comparator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.util.*;

class Student {
String name;
int score;

public Student(String name, int score) {
this.name = name;
this.score = score;
}

@Override
public String toString() {
return "Name: " + name + ", Score: " + score;
}
}

public class SortTest {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
list.add(new Student("Alice", 85));
list.add(new Student("Bob", 90));
list.add(new Student("Charlie", 85)); // 同分测试
list.add(new Student("David", 95));

// 核心排序逻辑
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 1. 先按成绩降序 (从大到小: o2 - o1)
if (o1.score != o2.score) {
return o2.score - o1.score;
}
// 2. 成绩相同按名字升序 (String 自带 compareTo)
return o1.name.compareTo(o2.name);
}
});

// 打印结果
for (Student s : list) {
System.out.println(s);
}
}
}

2. 接口与多态 (instanceof)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 1. 接口
interface USB {
void open();
void close();
}

// 2. 实现类
class Mouse implements USB {
public void open() { System.out.println("鼠标连接"); }
public void close() { System.out.println("鼠标断开"); }
}

class Keyboard implements USB {
public void open() { System.out.println("键盘连接"); }
public void close() { System.out.println("键盘断开"); }
}

// 3. 笔记本类
class Laptop {
public void useUSB(USB usb) {
usb.open(); // 多态调用

// 进阶考点:向下转型
if (usb instanceof Mouse) {
System.out.println("进行点击操作");
} else if (usb instanceof Keyboard) {
System.out.println("进行打字操作");
}

usb.close(); // 多态调用
}
}

// 4. 测试
public class InterfaceTest {
public static void main(String[] args) {
Laptop laptop = new Laptop();
laptop.useUSB(new Mouse());
System.out.println("---");
laptop.useUSB(new Keyboard());
}
}

3. IO 流与异常处理 (Try-with-Resources)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.io.*;

public class FileCopyTest {
public static void main(String[] args) {
// 使用 Try-with-Resources 语法 (Java 7+)
// 在圆括号中定义流,结束后会自动调用 close(),无需 finally
try (
// 输入流:读取 source.txt
BufferedReader reader = new BufferedReader(new FileReader("source.txt"));
// 输出流:写入 dest.txt
PrintWriter writer = new PrintWriter(new FileWriter("dest.txt"))
) {
String line;
// 逐行读取
while ((line = reader.readLine()) != null) {
// 转大写
String upperLine = line.toUpperCase();
// 写入新文件
writer.println(upperLine);
}
System.out.println("文件处理完成!");

} catch (IOException e) {
e.printStackTrace();
System.out.println("文件操作发生错误");
}
}
}