前言
本门课程主要采用了线上线下结合教学的方式,刷学堂在线的网课以及作业
辅助线下教学,来完成主要的课时任务。同时,一共进行了5次实验,11次
PTA作业,以及2次迭代程序博客总结,通过一步步学习,从难以理解到逐
步熟悉与掌握。
面向对象技术总结
一,封装
“封装”是面向对象编程的一个基础核心概念,是基石。在我们接触JAVA
之初就了解了什么是封装。简而言之,封装就是把数据(属性)和操作数据
的行为(方法)打包到一个类里,然后通过创建该类的对象来访问属性成员
和方法成员,从而实现数据安全、代码隔离和可维护性。
1.合理的封装应遵循以下原则
(1)职责单一原则:每个类或方法应专注于单一功能,避免职责扩散。
(2)最小暴露原则:仅对外提供必要的方法,隐藏内部实现。
(3)数据验证原则:通过setter或构造器验证输入参数,确保数据合法性。
2.封装主要通过以下两个机制实现
(1)访问修饰符(控制类、属性和方法的访问权限)
private:仅在类内部可见。
protected:在类内部及子类中可见,同一包内也可访问。
public:全局可见。
default(默认,无修饰符):仅在同一包内可见。
| 修饰符 | 类内 | 同包 | 子类(不同包) | 其他包 |
|---|---|---|---|---|
| private | ✔️ | ❌ | ❌ | ❌ |
| default(无修饰符) | ✔️ | ✔️ | ❌ | ❌ |
| protected | ✔️ | ✔️ | ✔️ | ❌ |
| public | ✔️ | ✔️ | ✔️ | ✔️ |
(2)Getter/Setter 方法:间接访问和修改私有属性,实现获取数据值以及赋值。
3.封装的实践案例
(1)学生类设计
点击查看代码
public class Student {
private String id; // 学号
private String name; // 姓名
private int age; // 年龄
private double score; // 成绩
// 构造方法
public Student(String id, String name, int age, double score) {
this.id = id;
this.name = name;
setAge(age); // 使用setter进行参数验证
setScore(score); // 使用setter进行参数验证
}
// Getter方法
public String getId() { return id; }
public String getName() { return name; }
public int getAge() { return age; }
public double getScore() { return score; }
// Setter方法(带参数验证)
public void setAge(int age) {
if (age > 0 && age < 150) { // 年龄验证
this.age = age;
} else {
throw new IllegalArgumentException("年龄必须在0-150之间");
}
}
public void setScore(double score) {
if (score >= 0 && score <= 100) { // 成绩验证
this.score = score;
} else {
throw new IllegalArgumentException("成绩必须在0-100之间");
}
}
}
(2) 银行账户类设计
点击查看代码
public class BankAccount {
private String accountNumber;
private double balance;
private boolean isActive;
// 私有方法:内部使用,不对外暴露
private void logTransaction(String action, double amount) {
System.out.println("账户 " + accountNumber + " 执行 " + action + " 金额: " + amount);
}
// 公共方法:提供安全的存款操作
public void deposit(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("存款金额必须为正数");
}
if (!isActive) {
throw new IllegalStateException("账户已冻结");
}
balance += amount;
logTransaction("存款", amount);
}
// 公共方法:提供安全的取款操作
public void withdraw(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("取款金额必须为正数");
}
if (amount > balance) {
throw new IllegalStateException("余额不足");
}
if (!isActive) {
throw new IllegalStateException("账户已冻结");
}
balance -= amount;
logTransaction("取款", amount);
}
// Getter和其他公共方法...
}
二,继承
继承是一种“是”的关系。子类一定是父类,但父类不一定是子类。允许一
个类(子类 / 派生类)继承另一个类(父类 / 基类)的属性和方法,并添加
新特性或修改原有功能。但是,子类并不是父类的一个子集,因为子类在继
承了父类的所有属性与方法后,仍然可以拓展父类不具备的属性与方法,这
就让他存在与父类无交集的一部分了。继承是面向对象编程中实现 “代码
复用” 和 “类型扩展” 的重要机制。
1.继承的语法实现
(1)extends关键字
点击查看代码
// 父类(基类)
public class ParentClass {
protected int commonField;
public void commonMethod() {}
}
// 子类(派生类)使用extends关键字继承父类
public class ChildClass extends ParentClass {
private int childField;
public void childMethod() {}
// 重写父类方法
@Override
public void commonMethod() {
super.commonMethod(); // 调用父类实现
// 子类特有的逻辑
}
}
(2)super关键字
点击查看代码
class Parent {
Parent() { System.out.println("Parent构造器"); }
Parent(int x) { System.out.println("Parent带参构造器"); }
}
class Child extends Parent {
// 显式调用父类带参构造器
Child() {
super(10); // 必须位于构造器首行
System.out.println("Child构造器");
}
}
tips. super 关键字的三种用法
| 用法场景 | 示例代码 | 说明 |
|---|---|---|
| 调用父类构造器 | super(参数); | 必须在子类构造器首行 |
| 调用父类方法 | super.method(); | 覆盖方法中调用父类实现 |
| 访问父类属性 | super.field; | 当子类有同名属性时区分访问 |
2.继承中的访问控制规则
| 修饰符 | 子类(同包) | 子类(不同包) | 非子类(同包) | 非子类(不同包) |
|---|---|---|---|---|
| private | ❌ | ❌ | ❌ | ❌ |
| default | ✅ | ❌ | ✅ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
3.继承的层次结构与类图表示

4.继承中的方法覆盖规则
| 父类方法 | 子类重写要求 | 示例 |
|---|---|---|
| public void f() | 子类方法必须为public | 不能降低访问权限 |
| protected void f() | 子类方法可为protected或public | 可提升访问权限 |
| private void f() | 无法重写(子类不可见) | 子类可定义同名方法但非重写 |
| final void f() | 无法重写(父类方法被 final 修饰) | 编译报错 |
5.继承的注意事项
(1)JAVA不支持多继承!(除非是接口,一个类可以实现多个接口,相当于多继承)
(2)方法重写规则:子类重写方法的访问修饰符必须不低于父类方法的访问修饰符。
(3)构造函数不能被继承
子类无法继承父类的构造函数,但必须通过super()调用父类构造函数。
若父类没有无参构造函数,子类必须显式调用父类的带参构造函数。
(4)final类/方法不可继承/重写
三,多态
多态是面向对象编程的三大特性之一(封装、继承、多态),其核心思想是 “同一接口,多种实现”。通过多态,可在运行时根据实际对象类型动态决定调
用哪个方法,实现代码的灵活性和可扩展性。
1.核心机制:
(1)编译时多态(静态绑定):通过方法重载(Overload)实现。
(2)运行时多态(动态绑定):通过方法重写(Override)和向上转型实现。
2.运行的三个必要条件

3.多态的基本实现
点击查看代码
// 父类:动物
class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
// 子类:猫
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}
// 子类:狗
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
}
// 测试多态
public class Main {
public static void main(String[] args) {
Animal a1 = new Cat(); // 父类引用指向子类对象
Animal a2 = new Dog();
a1.makeSound(); // 输出:喵喵喵(运行时动态绑定)
a2.makeSound(); // 输出:汪汪汪
}
}
点击查看代码
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle());
shapes.add(new Rectangle());
for (Shape shape : shapes) {
shape.draw(); // 动态调用子类实现
}
4.动态绑定的过程

5.多态的注意事项
(1)属性不支持多态
(2)静态方法不支持多态
四,抽象类
抽象类是一种特殊的类,它不能被实例化,主要用于为子类提供一个公共的抽象模板。抽象类可以包含抽象方法(没有方法体的方法)和具体方法。其核心思
想是将一些具有共性的属性和方法提取到抽象类中,让子类去实现具体的逻辑,从而实现代码的复用和扩展。
1.语法实现
使用abstract关键字修饰类和方法:
点击查看代码
// 抽象类
abstract class Shape {
// 抽象方法,没有方法体,以分号结尾
abstract double getArea();
// 具体方法
void display() {
System.out.println("这是一个图形");
}
}
// 子类继承抽象类并实现抽象方法
class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
double getArea() {
return Math.PI * radius * radius;
}
}
2.抽象类规则
| 特性 | 说明 |
|---|---|
| 实例化 | 抽象类不能被实例化,如 Shape shape = new Shape(); 会编译报错 |
| 继承 | 子类必须实现抽象类中的所有抽象方法(除非子类也是抽象类) |
| 成员 | 抽象类可以包含成员变量、构造函数、具体方法和抽象方法 |
3.注意事项与常见误区
(1)抽象类与抽象方法关系:抽象类不一定包含抽象方法,但包含抽象方法的类必须声明为抽象类。
(2)构造函数作用:抽象类可以有构造函数,用于初始化子类共有的属性,但不能直接实例化抽象类。
(3)子类实现要求:子类实现抽象方法时,访问修饰符不能比抽象方法更严格,例如抽象类中抽象方法为 protected,子类实现时不能为 private。
五,接口
接口是一种完全抽象的类型,它只包含常量和抽象方法(Java 8 及以后版本支持默认方法和静态方法)。接口用于定义一组规范或契约,实现接口的类必须
实现接口中定义的所有抽象方法,从而保证不同类之间具有统一的行为标准。
1.语法实现与关键特性
使用 interface 关键字定义接口:
点击查看代码
// 接口
interface Flyable {
// 常量(默认 public static final)
int MAX_SPEED = 100;
// 抽象方法(默认 public abstract)
void fly();
// Java 8 新增默认方法
default void takeOff() {
System.out.println("准备起飞");
}
// Java 8 新增静态方法
static void land() {
System.out.println("降落");
}
}
// 类实现接口
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟儿飞翔");
}
}
2.接口规则
| 特性 | 说明 |
|---|---|
| 实现 | 一个类可以实现多个接口,弥补 Java 单继承的不足 |
| 成员 | 接口中的属性默认是 public static final,方法默认是 public abstract |
| 继承 | 接口可以继承多个接口,使用 extends 关键字 |
3.注意事项与常见误区
(1)接口与抽象类区别:
接口中所有方法默认是抽象的,抽象类可以包含具体方法。
一个类只能继承一个抽象类,但可以实现多个接口。
(2)默认方法与静态方法:
默认方法允许在接口中提供方法的默认实现,实现类可以选择覆盖。
静态方法属于接口本身,通过接口名直接调用,不能被子类继承或重写。
(3)接口属性特点:接口中的属性必须初始化且不能被修改,因为其本质是常量。
六,集合框架
Java 集合框架是一组用于存储和操作数据的类和接口,提供了对数据进行
组织、管理和处理的统一方式。它包含了多种数据结构(如列表、集合、映
射),根据不同的需求选择合适的集合类,以提高数据处理的效率和灵活
性。
1.主要涉及的接口和实现的类

2.常用接口与类
| 接口 / 类 | 特点 | 数据结构 | 典型应用 |
|---|---|---|---|
| List | 有序、可重复 | 数组或链表 | 存储学生名单 |
| ArrayList | 基于数组,随机访问快,增删慢 | 动态数组 | 频繁查询场景 |
| LinkedList | 基于链表,增删快,随机访问慢 | 双向链表 | 频繁插入删除场景 |
| Set | 无序、唯一 | 哈希表或红黑树 | 去重操作 |
| HashSet | 基于哈希表,查询快 | 哈希表 | 快速判断元素是否存在 |
| Map | 键值对存储 | 哈希表或红黑树 | 存储用户信息(用户名 - 用户对象) |
| HashMap | 非线程安全,性能高 | 哈希表 | 一般键值对存储场景 |
| TreeMap | 按键排序,线程不安全 | 红黑树 | 需要按键有序存储的场景 |
3.注意事项与常见误区
(1)线程安全问题:大部分集合类(如 ArrayList、HashMap)是非线程安全的,在多线程环境下使用时需要额外的同步措施,或选择线程安全的集合类(如 Vector、ConcurrentHashMap)。
(2)泛型使用:合理使用泛型可以提高类型安全性,避免类型转换异常,如 List
(3)性能选择:根据实际需求选择合适的集合类,例如需要频繁插入删除操作时选择 LinkedList,需要快速随机访问时选择 ArrayList。
七,异常
异常是程序运行过程中出现的错误或意外情况。Java 通过异常处理机制,
提供了一种结构化的方式来捕获、处理和抛出异常,使程序在遇到错误时能
够优雅地处理问题,而不是直接崩溃,从而提高程序的稳定性和健壮性。
1.异常体系结构

解释如下:
(1)Throwable:所有异常和错误的基类。
(2)Error:表示严重的系统错误,如 OutOfMemoryError,程序一般无法处理。
(3)Exception:分为受检异常(Checked Exception)和非受检异常(Unchecked Exception):
① 受检异常:必须在方法中声明或者使用 try-catch 捕获,如 IOException、SQLException。
② 非受检异常:继承自 RuntimeException,如 NullPointerException、IllegalArgumentException,不需要强制处理。
2.异常处理的语法
(1)try-catch-finally 结构
try { // 可能抛出异常的代码 FileReader reader = new FileReader("file.txt"); } catch (FileNotFoundException e) { // 捕获异常并处理 System.out.println("文件未找到:" + e.getMessage()); } finally { // 无论是否发生异常,都会执行的代码 System.out.println("执行 finally 块"); }
(2)throw 与 throws
throw:在方法内部手动抛出异常对象,如 throw new IllegalArgumentException("参数不合法");。
throws:在方法声明中声明该方法可能抛出的异常,如 void readFile() throws IOException。
3.注意事项与常见误区
(1)捕获粒度问题:避免捕获过于宽泛的异常类型(如 catch (Exception e)),应尽量捕获具体的异常,以便更准确地处理问题。
(2)finally 块执行规则:finally 块中的代码一般会执行,但在某些特殊情况下(如 System.exit(0))可能不会执行。
(3)自定义异常:合理定义自定义异常类,继承自 Exception(受检异常)或 RuntimeException(非受检异常),根据业务需求选择合适的类型。
八,JavaFX(GUI 开发)
JavaFX 是 Java 平台用于构建富客户端应用程序的框架,提供了一套用于
创建图形用户界面(GUI)的 API。它支持多种 UI 组件(如按钮、文本
框、图表)、布局管理和动画效果,旨在替代传统的 Swing 框架,为开发
者提供更现代、更灵活的 GUI 开发体验。
1.主要组件
| 组件类型 | 示例 | 用途 |
|---|---|---|
| 控件(Controls) | Button、TextField、ComboBox | 与用户交互的元素 |
| 布局(Layouts) | VBox、HBox、GridPane | 管理控件的排列方式 |
| 场景(Scene) | 包含所有 UI 元素的容器 | 一个 Stage 只能有一个 Scene |
| 舞台(Stage) | 应用程序窗口 | 是 JavaFX 应用的顶级容器 |
| 节点(Node) | 所有节点都是 javafx.scene.Node 的子类 | 附加到场景图的所有组件 |
2.代码示例
点击查看代码
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class JavaFXExample extends Application {
@Override
public void start(Stage primaryStage) {
Button button = new Button("点击我");
VBox layout = new VBox(10);
layout.getChildren().add(button);
Scene scene = new Scene(layout, 300, 200);
primaryStage.setTitle("JavaFX 示例");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
3.常用类
3.1. 基础类
| 类名 | 功能描述 |
|---|---|
| Application | JavaFX 应用程序的基类,必须继承并实现start(Stage)方法作为入口。 |
| Stage | 应用程序窗口,包含标题栏、边框和内容区域。 |
| Scene | 可视内容的容器,必须设置到 Stage 上才能显示。 |
3.2. UI控件类
| 类名 | 功能描述 |
|---|---|
| 按钮类 | |
| Button | 普通可点击按钮。 |
| ToggleButton | 可切换状态的按钮(选中 / 未选中)。 |
| RadioButton | 单选按钮,需配合ToggleGroup使用。 |
| CheckBox | 复选框,支持多选。 |
| 文本类 | |
| Label | 静态文本标签。 |
| TextField | 单行文本输入框。 |
| TextArea | 多行文本输入框。 |
| PasswordField | 密码输入框,显示掩码字符。 |
| 选择类 | |
| ComboBox | 下拉选择框。 |
| ListView | 垂直列表视图。 |
| TableView | 表格视图,支持多列数据展示。 |
| TreeView | 树形结构视图。 |
| 进度类 | |
| ProgressBar | 水平进度条。 |
| ProgressIndicator | 圆形进度指示器。 |
| 对话框类 | |
| Alert | 预定义对话框(信息、警告、错误等)。 |
3.3. 布局容器类
| 类名 | 功能描述 |
|---|---|
| Pane | 最基本的容器,需手动设置子节点位置。 |
| HBox | 水平排列子节点。 |
| VBox | 垂直排列子节点。 |
| GridPane | 网格布局,按行列排列子节点。 |
| BorderPane | 分为顶部、底部、左侧、右侧和中央五个区域。 |
| StackPane | 层叠布局,子节点按添加顺序堆叠。 |
| FlowPane | 流式布局,自动换行或换列。 |
| TilePane | 平铺布局,所有子节点大小相同。 |
3.4. 图形与绘图类
| 类名 | 功能描述 |
|---|---|
| 形状类 | |
| Rectangle | 矩形。 |
| Circle | 圆形。 |
| Ellipse | 椭圆。 |
| Line | 线段。 |
| Path | 自定义路径,支持贝塞尔曲线等。 |
| 填充与效果类 | |
| Color | 颜色类,支持 RGB、HSB 等模式。 |
| LinearGradient | 线性渐变。 |
| RadialGradient | 径向渐变。 |
| DropShadow | 阴影效果。 |
| BlurType | 模糊效果。 |
3.5. 动画类
| 类名 | 功能描述 |
|---|---|
| TranslateTransition | 位置移动动画。 |
| ScaleTransition | 缩放动画。 |
| RotateTransition | 旋转动画。 |
| FadeTransition | 透明度变化动画。 |
| FillTransition | 形状填充颜色变化动画。 |
| PathTransition | 沿路径移动动画。 |
| ParallelTransition | 并行执行多个动画。 |
| SequentialTransition | 顺序执行多个动画。 |
| Timeline | 基于关键帧(KeyFrame)的复杂动画。 |
3.6. 事件处理类
| 类名 | 功能描述 |
|---|---|
| Event | 所有事件的基类。 |
| MouseEvent | 鼠标事件(点击、移动、拖拽等)。 |
| KeyEvent | 键盘事件(按键按下、释放等)。 |
| ActionEvent | 动作事件(按钮点击、菜单项选择等)。 |
| EventHandler | 事件处理器接口。 |
| EventTarget | 事件目标接口。 |
| EventDispatchChain | 事件分发链。 |
3.7. 属性与绑定类
| 类名 | 功能描述 |
|---|---|
| ObservableValue | 可观察值接口。 |
| Property | 属性接口,继承ObservableValue。 |
| SimpleStringProperty | 字符串属性实现。 |
| SimpleIntegerProperty | 整数属性实现。 |
| SimpleBooleanProperty | 布尔属性实现。 |
| Bindings | 提供各种绑定方法的工具类。 |
踩坑心得
在学习初期,对 Java 的面向对象编程思想理解不透彻,特别是从多态等概念开始就会有点难以理解。在设计类的继承关系时,未合理规划父类与子类的属性和方法,导致代码冗余且难以维护。在后续学习中,通过绘制类图、编写小型示例代码并调试,逐步加深了对这些概念的理解。同时,在学习 Java 的异常处理机制时,曾简单地将所有异常都捕获处理,未考虑到异常的合理分类与抛出,导致程序出现问题时难以定位根源。后来通过学习不同类型异常的特点,明确了何时捕获、何时抛出,提升了代码的健壮性。
Java 语法细节繁多,在使用数组、集合、泛型等知识点时,容易出现边界条件考虑不全的问题。如在数组遍历中,常因下标越界导致程序崩溃;在使用 HashMap 时,忽略了键值对的唯一性要求,出现数据覆盖。解决这类问题,关键在于多做练习,编写代码后进行全面测试,利用调试工具逐步排查错误,加深对语法规则的印象。另外,在 Lambda 表达式的学习中,由于对其语法和使用场景不熟悉,花了很长一段时间才能理解,达到基本上掌握,编写的代码既复杂又低效。后来结合实际业务需求反复练习,才掌握了它们的高效使用方式。
改进建议和总结
PTA作业是巩固知识的重要环节,目前的作业难度梯度设置较为合理。对于PTA平台的测试点解释,每次测试点错误时,不太能理解这个测试点到底是什么意思,就得自己逐一调试排查,不过这也是一种训练调试能力的方式,希望至少当习题集结束时,可以对每个测试点所检测的内容有所解释,帮助理解,与他方面如课堂教学和实验均良好,暂无建议。
浙公网安备 33010602011771号