2026/9/19 19:08:37

Java期末考试复习:封装继承多态与JShell实操技巧

Java期末考试复习:封装继承多态与JShell实操技巧 简介这份《面向对象程序设计JAVA语言程序设计》期末考试试题及部分答案面向Java课程复习阶段的本科、高职学生可作考前自测与查漏补缺之用。资源已整理为单文件PDF文档压缩包约437KB体积精炼便于手机、平板或电脑端随时翻阅。试题分为十六个选择题与八个填空题内容覆盖类与对象、继承关系、方法重载与成员覆盖、接口、异常处理、switch执行逻辑、浮点数比较精度、String与StringBuffer区别以及Unicode编码等高频考点选择题侧重易混淆概念辨析填空题侧重基础语法与机制记忆部分题目附有参考答案便于边练边核对、快速定位薄弱环节。目前已有1586人学习下载对掌握Java面向对象思想并应对期末笔试具有较强参考价值。1. 这门期末考试真正要交差的是“用 Java 写出面向对象的程序”不是背语法《面向对象程序设计JAVA语言程序设计》这类课程的名称往往比实际考试内容长但期末试卷却非常统一选择、填空、简答、读程序、编程题。很多学生复习时死记硬背“面向对象特征有封装继承多态”结果一拿到读程序题就判断错重载与重写的调用结果或者写五行的类定义都能把构造方法名写错。其实这门课的考试目标很实际考察你是否能用 Java 语言把现实问题拆成对象、用类组织状态和行为、用继承和多态解决扩展问题。换句话说面向对象程序设计考的是“抽象出来的代码长什么样”而不是概念原文。文章会按试卷常见题型拆考点每一节给出可直接复用的代码和参数说明最后告诉你如何在考场上快速验证一个拿不准的 Java 语法点这对已经工作但想补基础的 Java 工程师也有参考价值因为很多 Java 面试题就是从这些期末考试题变体来的。2. 封装、继承、多态试卷里反复出现的三个得分区所谓理论先行但是考试里最直接给分的题目往往是把理论放到代码里让你判断。我们需要把三个特性拆开看每一个都对应一种固定的考法。2.1 封装私有成员变量与 getter/setter 的固定写法封装的考点非常单调主要考访问权限和对外提供方法。最典型的一道填空题是“成员变量使用______修饰外部不能直接访问只能通过______方法访问。”答案就是 private 和 getter/setter。但编程题不会让你填空它会要求你写一个类把属性设为私有并提供访问器。下面是最标准的实现模板public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { this.name name; this.age age; } public String getName() { return name; } public void setName(String name) { this.name name; } public int getAge() { return age; } public void setAge(int age) { // 这里可以做有效性校验 if (age 0 || age 150) { throw new IllegalArgumentException(年龄不合法); } this.age age; } }这段代码要注意三个细节。第一字段全部 private这是封装的第一道边界第二构造方法可以有多个无参构造和带参构造可以共存这一点经常考第三setter 里可以加参数校验这是加分项说明你理解封装的意义在于控制数据有效性。Java 中访问修饰符的可访问范围是一个容易出选择题的点需要记忆的关系如下修饰符同类内同包内子类跨包全局private可访问不可不可不可默认不写可访问可访问不可不可protected可访问可访问可访问不可public可访问可访问可访问可访问注意protected 允许在同一包内任意访问也允许不同包内的子类通过继承关系访问但不能通过父类引用来访问子类对象里继承来的 protected 成员。这种细节是简答题“为什么使用封装”之后最常见的引申考点。2.2 继承构造器调用顺序和 super 的行号问题继承部分的读程序题通常是这样的父类和子类都有构造器然后 new 子类对象问你输出顺序。比如下面代码class Animal { public Animal() { System.out.println(Animal 构造器); } } class Dog extends Animal { public Dog() { // 这里其实隐式调用了 super() System.out.println(Dog 构造器); } } public class Main { public static void main(String[] args) { Dog d new Dog(); } }输出结果是Animal 构造器 Dog 构造器原因是子类构造器执行之前必须完成父类构造。Java 编译器会在子类构造器第一行自动插入super()除非你显式写了super(参数)或this(参数)。如果父类没有无参构造而子类构造器又没有显式调用 super编译会直接报错。这常被拿来写改错题父类只有带参构造子类构造器没有写super(name)编译无法通过。如果你想控制父类构造参数写法是class Cat extends Animal { public Cat(String name) { super(name); // 必须放在第一行 } }这里第一行只能写super(参数)或者this(参数)不能同时写。另一个考点是静态成员是否被继承Java 中静态成员可以被子类通过继承访问但本质上静态成员属于类本身不参与重写。读程序题里如果父类和子类都有同名的 static 方法通过父类引用调用时执行的是父类版本这与实例方法的重写行为不同。2.3 多态向上转型和向下转型的边界条件多态是三个特性中考试权重最高的。选择题的高频考法如下class Father { void say() { System.out.println(Father); } } class Son extends Father { Override void say() { System.out.println(Son); } } Father obj new Son(); obj.say();这段代码输出Son。原理是编译期只检查引用类型 Father 有没有say()方法运行期则调用实际对象 Son 的版本这叫做动态绑定。如果子类新增了一个方法walk()那么Father obj new Son(); obj.walk();会编译失败因为 Father 中没有这个方法。至于向下转型前提是对象原本就是子类实例。典型错误题是Father f new Father(); Son s (Son) f; // 运行时抛出 ClassCastException记住一句话向上转型是安全的向下转型必须先用instanceof做检查。考试中如果你不确定某个引用调用的结果是哪一个类的方法直接画一条“引用指向对象”的线看方法的定义从谁开始找运行版本找实际对象。3. 重载重写、final 和 static易错选择题背后的语法边界复习到一定阶段你会发现选择填空的失分点基本集中在这几个语法特性上。它们单独看都容易理解放在一起就是一组一组的“坑”。3.1 重载与重写的区别从方法签名到异常限制重载是在同一个类里方法名相同、参数列表不同重写是子类对父类同名同参方法的重新实现。以下代码同时出现两种现象class Base { public String getInfo() { return Base; } } class Child extends Base { // 方法名相同参数不同这是重载吗不是因为一个是继承一个是新增。 public String getInfo(int x) { return Child param: x; } // 参数列表与父类一致这是重写 Override public String getInfo() { return Child; } }考试判断题可能会说“子类中定义一个和父类同名但参数不同的方法是重写”这是错的应该叫重载。重载与重写可以用表格区分对比项重载重写位置同一个类内子类和父类之间方法名相同相同参数列表必须不同必须完全一致返回类型可以不同不限制必须相同或父类返回类型的子类型访问权限任意不能比父类更严格抛出异常无限制不能抛出比父类更宽泛的异常这个表格中的前四行是必须背下来的。做题时如果看到“重写方法的返回类型可以不同”反例是父类返回Number子类返回Integer是允许的这叫做协变返回类型。但如果父类返回Object子类返回String也可以因为 String 是 Object 的子类。如果父类返回String子类返回Object就编译错误。3.2 final 和 static 的组合陷阱初始化顺序与不可变final修饰变量表示常量修饰方法表示不能重写修饰类表示不能继承。static修饰成员表示属于类而不是实例。两个关键字放在一起时最常考的题目是“以下哪种写法会编译失败”。例如class Demo { static final int MAX 10; // 正确编译期常量 final static int MIN; // 正确static final 可以在静态代码块初始化 static { MIN 1; } final int count; // 正确final 实例变量可以在构造器初始化 // 下面这行错误static final 变量不能在构造器里赋值 // public Demo() { MIN 2; } }关于初始化顺序读代码题里经常出现静态代码块、实例代码块和构造器的输出顺序。简单规则是程序加载类时先执行 static 变量和 static 代码块顺序按代码书写顺序创建对象时先执行实例变量和实例代码块再执行构造器。如果子类继承父类则先执行父类的静态块再执行子类的静态块创建对象时先执行父类的实例块和构造器再执行子类的实例块和构造器。这种题目花三分钟手写一遍过程基本不会错。3.3 this 和 super 的定位差异简答题的标准答法简答题常问“this 和 super 的区别”。标准答案需要写三点第一this 指向当前对象引用super 是父类对象的引用但更准确的说法是“用 super 来访问父类成员”第二this()调用当前类构造器super()调用父类构造器两者都必须写在构造器第一行所以不能同时出现第三this 可以单独作为返回值返回当前对象super 不能单独存在并传递。比如写链式调用时public class Person { private int age; public Person setAge(int age) { this.age age; return this; } }但如果你试图用 super 做类似的事情写成return super;编译不会通过因为 super 不是对象引用它只是“从当前对象视角访问父类成员”的语法标记。这一点答题时最好明确说“super 不是引用变量”面试里也很容易作为 Java 面试题出现。4. 综合编程大题从类设计到集合输出的完整解题流程期末考试最后一道题通常是合并考察封装、构造器、集合、排序、输入输出。题目往往类似“设计一个图书管理类实现添加图书、按价格排序输出”。这个部分我们要把整个解法和代码逻辑都梳理一遍因为编程题给分的点非常固定。4.1 典型题目和最小可运行代码题目要求定义 Book 类属性书名和价格进行封装定义 Library 类内部用 ArrayList 保存 Book通过构造器传入初始数据添加 addBook 方法按价格升序输出。import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class Book { private String title; private double price; public Book(String title, double price) { this.title title; this.price price; } public String getTitle() { return title; } public double getPrice() { return price; } Override public String toString() { return title : price; } } class Library { private ListBook books; public Library() { books new ArrayList(); } public void addBook(Book book) { books.add(book); } public void sortByPrice() { books.sort(Comparator.comparingDouble(Book::getPrice)); } public void printBooks() { for (Book b : books) { System.out.println(b); } } } public class Main { public static void main(String[] args) { Library lib new Library(); lib.addBook(new Book(Java程序设计, 89.5)); lib.addBook(new Book(数据结构, 59.0)); lib.addBook(new Book(操作系统, 78.0)); lib.sortByPrice(); lib.printBooks(); } }这段代码使用了ArrayList的sort方法和Comparator.comparingDouble函数式接口这是比较新的 Java 8 以后写法。如果你的教材版本比较老试卷可能要求实现Comparable接口public class Book implements ComparableBook { // 省略其他代码 Override public int compareTo(Book other) { return Double.compare(this.price, other.price); } }注意Double.compare是必须的因为直接写(int)(this.price - other.price)在价格差小于 1 时会截断为 0导致排序错误。这个坑在编程题里几乎每年能看到几个学生踩中。4.2 阅卷给分点你的代码哪一行在得分综合题的给分原则并不是只要求能运行。大多数学校按以下明细给分考点分数分布常见扣分原因类的封装私有字段getter/setter30%字段写成 public 或没有 setter构造器定义15%构造器方法和类名不一致集合的创建和增删20%直接使用数组没有体现集合优势排序逻辑25%排序后忘记写输出或 Comparator 使用错误代码可读性和命名规范10%main 方法里堆大量逻辑如果你想要一个稳妥的答题结构建议先写实体类 Book再写管理类 Library最后在 main 里调用。不要把所有代码都写进 main这会直接丢掉可读性分数。同时注意Book的字段定义为private然后提供getter如果需要修改再提供setter。很多同学习惯把 setter 全部写上但有些字段在对象初始化之后根本不应该变比如图书的 ID这类字段只提供 getter 就好。这也是考试中“设计是否正确”的隐含考察点。4.3 异常处理与常见秋招 Java 面试题的交叉编程题有时还会附加问一句“如果添加的图书价格为负数程序会不会崩溃”如果你有异常处理意识可以在 setPrice 中加校验public void setPrice(double price) { if (price 0) { throw new IllegalArgumentException(价格不能为负数); } this.price price; }然后调用方可以用 try-catch 捕获。这一部分考点其实和 Java 后端开发的日常非常接近。换句话说期末考试不只是学期任务很多基础概念这些年直接被拿来当 Java 面试八股文比如“接口和抽象类的区别”“ArrayList 和 LinkedList 区别”“泛型的协变逆变”。如果你已经工作了几年偶尔回头翻翻这套题对那些基础问题的回答会更扎实。5. 考场上验证一个拿不准的 Java 语法点JShell 就是你的草稿纸最后一章我们专注于一个具体技巧遇到不确定的语法不要靠猜直接用 JShell 在一秒内得到结果。JShell 是 Java 9 之后自带的 REPL 工具期末考试环境下即使没有 IDE命令行里也大概率能用因为 JDK 安装目录的 bin 下会有 jshell 命令。它的价值在于你不必新建 java 文件不用写完整类结构可以直接输入语句验证。比如你想确认static方法能不能访问实例变量进入 JShell 后输入jshell class Foo { int x 1; static void m() { System.out.println(x); } }JShell 会直接报错提示非静态变量不能从静态上下文中引用。如果你想验证向上转型调用的是哪个方法直接写jshell class A { void f() { System.out.println(A); } } jshell class B extends A { void f() { System.out.println(B); } } jshell A a new B(); jshell a.f();输出 B结果一目了然。用 JShell 还有一个好处它可以执行多行代码块支持定义变量、方法、类甚至能重复定义同名类这对复习期间做零散验证非常方便。进入 JShell 后输入/vars可以查看所有变量/methods可以查看已定义方法/open可以加载外部文件。如果你所在机房没有 JShell也可以在 Linux 机器上使用java -X查看可用参数但最接近 JShell 的就是这个工具。关于手写代码时的验证顺序建议一个动作读代码题先画出继承关系树再标出哪些方法被重写哪些是重载最后确认引用类型和实际类型。编程题写完后如果允许编译第一时间检查类名和文件名是否一致然后是构造器首行有没有隐式的 super 调用最后是泛型集合的导入语句。最快的自测方法是把主方法里每个步骤的注释写在旁边比如“创建集合对象”注释本身能帮你发现逻辑断点。把这些动作养成习惯期末考试的“部分答案”其实就藏在你对自己的代码做的一次次追问里考场上的每一分都来自平时确信过的那一行。本文还有配套的精品资源点击获取