前言

本门课程主要采用了线上线下结合教学的方式,刷学堂在线的网课以及作业

辅助线下教学,来完成主要的课时任务。同时,一共进行了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平台的测试点解释,每次测试点错误时,不太能理解这个测试点到底是什么意思,就得自己逐一调试排查,不过这也是一种训练调试能力的方式,希望至少当习题集结束时,可以对每个测试点所检测的内容有所解释,帮助理解,与他方面如课堂教学和实验均良好,暂无建议。