第三次blog作业

(一)、前言
在完成这门面向对象课程的学习后,回顾整个学习历程,既有攻克难题的喜悦,也有陷入困境的迷茫。这门课程通过多样化的学习形式,如 Blog 作业、PTA 作业、实验、线上学堂在线以及线下课程,构建起了一个完整的知识体系。

  • Blog 作业要求我们对学习内容进行梳理、总结和反思,通过文字表达的形式加深对知识的理解和记忆。从最初对面向对象概念的懵懂阐述,到后期对复杂技术点的深入剖析,Blog 作业见证了我学习过程中的成长与进步。
    难度:论及难度,他不像是让你觉得无法完成,而是需要你静下心来思索自己在这个阶段的历程然后以精简的语言记录下来。所以写工程日志是一个好习惯。
  • PTA 作业则侧重于对编程知识的实践应用,每一道题目都是对特定知识点的专项训练。从基础的语法运用到复杂的算法实现,PTA 作业的难度呈阶梯式上升。初期的题目较为简单,主要帮助我们巩固课堂所学的基础知识,随着课程的推进,题目难度逐渐加大,涉及到多个知识点的综合运用,对我们的编程思维和代码实现能力提出了更高的要求。​
    难度:难度的话除了第一次对算法理解的要求有点高之外其他的其实都还行。如果只想要拿到的得分点的话那可能做PTA作业的意义遍大打折扣了。面向对象的核心并不是要求实现需求,而是采用一种怎样的模式实现需求,是否易于可扩展性,是否易于维护,在面临变化性大的要求是否能较快调整,这才是面向对象设计的内核。
  • 实验环节是将理论知识与实际项目相结合的重要途径。通过完成一系列的实验项目,我们能够更加深入地理解面向对象编程的思想和方法。。实验的工作量较大,尤其是在一些综合性较强的实验项目中,需要花费大量的时间进行需求分析、设计和开发。
    ​难度:从难度层面来看,作业设置对初学者还是比较友好的。任务围绕类的创建、对象的实例化、方法调用,javaFx的基础使用等基础要点展开,循序渐进引导掌握面向对象编程的基本使用方法。继承、封装等核心概念通过大象装进冰箱的具体案例步步递进,即便初次接触也能逐步理解。
  • 线上课程和线下课程相互补充,为我们提供了全面的学习资源。线上课程具有时间和空间上的灵活性,我们可以根据自己的学习进度和需求随时进行学习和复习。课程视频中对知识点的讲解细致入微,同时还配备了丰富的案例和练习题,帮助我们更好地理解和掌握知识。线下课程则为我们提供了与老师和同学面对面交流的机会,老师在课堂上会对重点和难点知识进行深入讲解,并通过实际的演示和案例分析,让我们更加直观地理解抽象的概念。
    难度:要学会这门课程难度其实不高,但是想要学懂并贯彻面向对象的核心理念实际编程还是具有一定的难度的,所以这也反映了学习编程语言的秘诀其实就是多练多实践才能一步步理解怎么用。
    面向对象编程 (OOP) 核心概念总结

(二)、面向对象编程 (OOP) 核心概念总结:
面向对象编程是一种以“对象”为中心的编程范式,它将数据和操作数据的方法捆绑在一起,形成具有特定属性和行为的实体。Java 是典型的 OOP 语言,其核心支柱是:

  1. 封装 (Encapsulation)
  • 概念: 将对象的属性(数据)和行为(方法)包装在一个单元(类)中,并隐藏对象的内部实现细节。通常通过访问修饰符 (private, protected, public) 来实现。

  • 目的:

数据隐藏: 保护对象的内部状态不被外部随意访问和修改,防止数据被意外篡改或不一致。

提高安全性: 只暴露必要的操作接口(通常是 public 方法)。

降低耦合: 外部代码只需通过公开的方法与对象交互,无需关心内部实现,提高代码的模块化和可维护性。

增强可维护性: 内部实现可以独立修改,只要公开的接口保持不变,就不会影响使用该对象的代码。

Java 实现: 使用 private 修饰属性,提供 public 的 getter (获取属性值) 和 setter (设置属性值) 方法来控制对属性的访问(也称为“数据封装”)。

  1. 继承 (Inheritance)
  • 概念: 允许一个类(子类、派生类)基于另一个类(父类、超类、基类)来创建,自动获得父类的属性和方法(非 private 的),并可以添加新的属性和方法,或覆盖父类的方法以实现特定行为。

  • 目的:

代码复用: 避免重复编写父类已有的代码。

建立类层次结构: 表达现实世界中“is-a”的关系(例如,Dog is an Animal)。

实现多态的基础: 子类对象可以被当作父类对象使用。

Java 实现: 使用 extends 关键字。Java 只支持单继承(一个子类只能有一个直接父类)。使用 super 关键字引用父类成员或调用父类构造器。

  1. 多态 (Polymorphism)
  • 概念: “多种形态”。指同一个操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在 Java 中主要体现在:

编译时多态(静态绑定/方法重载): 同一个类中,方法名相同但参数列表不同(类型、个数、顺序)。

运行时多态(动态绑定/方法重写): 最核心的多态形式。 子类继承父类后,可以重写 (@Override) 父类的方法。当父类引用指向子类对象时,调用被重写的方法,实际执行的是子类重写后的方法。

  • 目的:

接口统一: 允许使用父类类型的引用来操作不同的子类对象,代码更通用、灵活。

可扩展性: 添加新的子类类型时,无需修改基于父类编写的通用代码。

解耦: 调用者只关心接口(父类定义的方法),不关心具体实现(哪个子类)。

Java 实现: 方法重载、方法重写 (@Override)、父类引用指向子类对象(向上转型)、instanceof 操作符、向下转型(需谨慎)。

  1. 抽象类 (Abstract Class)
  • 概念: 使用 abstract 关键字修饰的类。它不能被实例化(即不能 new)。它可以包含:

抽象方法: 使用 abstract 修饰,只有声明没有实现(没有方法体)。子类必须重写所有抽象方法(除非子类也是抽象类)。

具体方法: 有实现的方法。

属性(字段)。

构造器: 虽然不能实例化,但构造器用于子类实例化时初始化继承的属性。

  • 目的:

定义模板/契约: 为相关类提供一个公共的基类模板,强制子类实现特定的行为(抽象方法)。

部分实现共享: 可以在抽象类中实现一些公共的具体方法,避免子类重复实现。

限制实例化: 表示该类是一个不完整的、需要进一步具体化的概念。

与普通类区别: 不能被实例化,可以包含抽象方法。

  1. 接口 (Interface)

概念: 使用 interface 关键字定义。它是一种完全抽象的类型,在 Java 7 及之前只能包含:

常量: 默认是 public static final。

抽象方法: 默认是 public abstract。

Java 8+ 增强:

默认方法 (default methods): 提供方法的默认实现。目的是在不破坏现有实现该接口的类的前提下,为接口添加新功能。

静态方法 (static methods): 属于接口本身的方法,通过接口名直接调用。

Java 9+ 增强:

私有方法 (private methods): 只能在接口内部使用,用于辅助默认方法或静态方法,减少代码重复。

目的:

定义行为契约: 明确规定一个类“能做什么”,而不关心“怎么做”。一个类通过 implements 关键字实现接口,就必须提供接口中所有抽象方法的实现(除非是抽象类)。

实现多重继承: Java 类只能单继承,但一个类可以实现多个接口。这是 Java 实现多重行为继承的主要方式。

解耦: 实现类只依赖于接口定义的抽象方法,不依赖于其他具体实现类。是实现“面向接口编程”和“依赖倒置原则”的关键。

替代标记接口: 在 Java 8 之前,接口常用于标记(如 Serializable),现在功能更强大。

与抽象类区别:

接口主要定义行为契约(能做什么),抽象类可以包含状态(属性)和部分实现(具体方法)。

类只能单继承抽象类,但可以实现多个接口。

接口成员默认都是 public,抽象类成员可以有各种访问修饰符。

接口不能有构造器,抽象类可以有(供子类调用)。

接口在 Java 8 之前是完全抽象的,之后可以包含默认和静态实现。

  1. 集合框架 (Collections Framework)

概念: Java 提供的一套用于存储和操作对象组(集合)的标准化、高性能的架构和实现。它是基于 OOP 思想设计的,核心接口位于 java.util 包。

核心接口 (体现多态):

Collection: 单列集合的根接口。定义了添加、删除、遍历等基本操作。主要子接口:

List: 有序集合,元素可重复,有索引。常用实现:ArrayList (数组,随机访问快,增删慢),LinkedList (链表,增删快,随机访问慢)。

Set: 无序集合,元素不可重复(基于 equals() 和 hashCode())。常用实现:HashSet (哈希表,最快,无序),LinkedHashSet (哈希表+链表,按插入顺序),TreeSet (红黑树,自然排序或定制排序)。

Map<K, V>: 双列集合,存储键值对 (Key-Value)。键不可重复(基于 equals() 和 hashCode())。常用实现:HashMap (哈希表,最快,无序),LinkedHashMap (按插入顺序或访问顺序),TreeMap (按键排序)。

OOP 应用:

多态: 编程时优先面向接口 (List, Set, Map, Collection, Iterator),而不是具体实现类 (ArrayList, HashSet, HashMap),使代码更灵活,易于替换实现。

封装: 集合类内部封装了复杂的数据结构(数组、链表、树、哈希表)。

泛型 (Generics): 集合框架的核心是泛型(, <K,V>),它提供了编译时类型安全,避免了运行时强制类型转换 (ClassCastException)。泛型本质也是参数化类型,是 OOP 的扩展。

迭代器模式 (Iterator Pattern): 通过 Iterator 接口提供了一种统一遍历不同集合元素的方式,隐藏了底层集合的内部结构。

  1. 异常处理 (Exception Handling)

概念: Java 提供的一种健壮的错误处理机制,用于处理程序运行时可能发生的非预期事件(错误或异常),防止程序崩溃,并允许程序进行恢复或优雅退出。

类层次结构 (体现继承):

Throwable: 所有错误或异常的顶级父类。

Error: 严重的、程序通常无法处理的系统级错误(如 OutOfMemoryError, StackOverflowError)。应用程序通常不捕获处理。

Exception: 程序本身可以处理的异常。主要分为:

RuntimeException (未检查异常 Unchecked Exception): 由程序逻辑错误导致(如 NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException, IllegalArgumentException)。编译器不强制要求处理(捕获或声明抛出)。

其他 Exception (已检查异常 Checked Exception): 通常由外部因素导致(如 IOException, SQLException, ClassNotFoundException)。编译器强制要求处理(必须 try-catch 捕获或在方法签名中用 throws 声明抛出)。

处理机制 (体现封装与流程控制):

try: 包含可能抛出异常的代码块。

catch: 捕获并处理特定类型的异常。可以有多个 catch 块(子类异常在前,父类在后)。

finally: 无论是否发生异常,总会执行的代码块(常用于释放资源,如关闭文件、数据库连接)。

throw: 在方法内部主动抛出一个异常对象。

throws: 在方法签名中声明该方法可能抛出的异常类型(主要是已检查异常),通知调用者需要处理这些异常。

自定义异常: 通过继承 Exception(检查异常)或 RuntimeException(未检查异常)来创建特定于应用程序的异常类,更好地封装错误信息。

OOP 思想:

封装: 将错误信息和处理逻辑封装在异常对象中。

继承: 异常类形成了清晰的层次结构,便于分类和处理(如捕获父类异常可以处理所有子类异常)。

多态: catch 块可以捕获其声明的异常类型及其所有子类类型。方法签名 throws 父类异常可以涵盖其子类异常。

  1. JavaFX

概念: Java 的下一代 GUI(图形用户界面)工具包,用于构建富客户端桌面应用程序、游戏和嵌入式应用。它是 Swing/AWT 的现代替代品。

核心 OOP 思想应用:

场景图 (Scene Graph) 与节点 (Node): GUI 被组织成一个树状的场景图。每个元素(按钮、文本框、布局面板、形状等)都是一个 Node 对象。这体现了组合关系(也是一种强关联关系) - 一个 Pane(布局面板)包含多个子 Node。

继承:

所有 UI 控件(Button, TextField, Label 等)都继承自 Control,最终继承自 Node。

布局容器 (Pane, VBox, HBox, GridPane, BorderPane 等) 继承自 Parent (也是一种 Node),负责管理子节点的位置和大小。

形状 (Rectangle, Circle, Line 等) 直接继承自 Shape (也是一种 Node)。

封装:

每个 Node 封装了自身的属性(位置、大小、颜色、文本、事件处理器等)和行为。

Stage (舞台) 封装了顶级窗口。

Scene (场景) 封装了场景图根节点和场景大小等。

事件驱动编程 (Event-Driven Programming) 与多态:

JavaFX 是典型的事件驱动模型。用户操作(点击、按键、鼠标移动)或系统事件会触发 Event 对象。

通过为 Node 注册事件处理器 (EventHandler) 来响应特定事件。

多态的核心体现:

EventHandler 是一个函数式接口(Java 8+),通常用 Lambda 表达式或方法引用实现。不同的 Node 可以注册相同类型事件(如 ActionEvent)但不同实现的处理器。

事件处理系统基于事件的类型 (MouseEvent, KeyEvent, ActionEvent 等) 进行分发,调用相应的处理器,这是运行时多态的典型应用。

属性绑定 (Property Binding) 与观察者模式: JavaFX 引入了强大的属性 (Property) 概念(如 StringProperty, IntegerProperty, BooleanProperty)。属性之间可以建立绑定关系(例如,一个标签的文本属性绑定到一个滑块的数值属性),当源属性改变时,目标属性自动更新。这背后使用了观察者模式,是对象间通信和解耦的重要机制。

CSS 样式化: 支持使用 CSS 来定义 UI 控件的样式(颜色、字体、边框等),将外观与逻辑进一步分离,体现了关注点分离的思想。

FXML: 一种基于 XML 的标记语言,用于描述 JavaFX 用户界面。允许将 UI 布局 (View) 与应用程序逻辑 (Controller) 和业务数据 (Model) 分离,便于设计和协作,是 MVC/MVVM 模式在 JavaFX 中的一种实现方式。

总结:Java 的面向对象技术提供了一套强大的工具和思想来构建复杂、可维护、可扩展的软件系统:

  • 封装保护数据并定义清晰的接口。

  • 继承促进代码复用和建立层次关系。

  • 多态(尤其是运行时多态)提供灵活性和代码通用性,是设计模式的基础。

  • 抽象类和接口是定义契约、实现多态和代码结构化的关键机制,接口在现代 Java 中尤其重要(多重继承、函数式编程)。

  • 集合框架基于 OOP 原则(多态、泛型、迭代器)提供了高效、类型安全的数据存储和操作能力。

  • 异常处理利用继承和多态构建了健壮的错误处理机制,保障程序稳定性。

  • JavaFX 将 OOP 思想(继承、封装、多态、组合、观察者模式)深入应用到 GUI 开发中,通过场景图、事件驱动、属性绑定、FXML/MVC 等特性,支持构建现代化的、响应式的用户界面。

(三)、 采坑心得与成长启示

在整门课程的学习过程中,走过的弯路是宝贵的财富,让我深刻理解了软件开发的实践真谛。以下是关键教训与获得的成长原则:

代码可读性是生产力的基石:

  • 踩坑: 早期代码结构混乱、命名随意、注释缺失,导致后期调试和维护举步维艰,严重拖累效率。

  • 领悟: 代码首先是给人读的,其次才是给机器执行的。 清晰的命名、合理的结构、必要的注释。

  • 行动指南:

    • 严格遵守命名规范: 使用有意义的驼峰命名法,让变量、方法、类名自解释(如 calculateTotalPrice() 优于 calc())。
    • 保持方法短小专注: 一个方法只做一件事。长方法往往是逻辑混乱的温床。
    • 注释解释“为什么”,而非“是什么”: 代码本身应说明“做什么”,注释重点解释复杂的逻辑、关键的算法选择、重要的约束条件等“为什么这么做”。避免无意义的注释。
    • 善用代码格式化工具: (如IDE的自动格式化) 保证风格统一。

调试:科学方法战胜盲目试错

  • 踩坑: 遇错即慌,凭感觉胡乱修改,结果陷入“改出一个错,引入两个新错”的恶性循环(尤其在PTA作业中)。

  • 领悟: 调试是侦探工作,需要证据和逻辑。 盲目修改如同蒙眼走路。

  • 行动指南:

    • 理解错误信息: 仔细阅读编译错误和运行时异常堆栈信息,它们是定位问题的第一线索。
    • 利用调试器: 掌握设置断点、单步执行、查看变量值、计算表达式等核心调试技能。亲眼观察程序执行流和状态变化是最可靠的手段。
    • 缩小问题范围: 通过注释代码、编写最小复现代码等方式,逐步隔离问题根源。
    • 打印日志辅助: 在关键节点输出变量状态(使用System.out.println或日志框架如SLF4J),尤其在不易使用调试器的场景(如多线程、部署环境)。

学习之道:深度理解优于浅尝辄止

  • 踩坑: 为赶进度(如集合框架、JavaFX实验),只求“会用”API,忽视底层原理和设计思想。结果面对稍复杂或变通需求就束手无策。

  • 领悟: “知其然”更要“知其所以然”。 扎实的基础和深刻的理解是应对复杂性和灵活创新的根本。

  • 行动指南:

    • 探究“为什么”: 学习API时,思考其设计目的、解决的问题、背后的数据结构/算法(如ArrayList vs LinkedList)。
    • 动手实践与反思: 不仅要完成实验/作业功能,更要尝试修改、破坏、重构代码,观察不同选择带来的结果,加深理解。
    • 阅读优质源码: 尝试阅读JDK核心类库或优秀开源项目的源码(从简单的类开始),学习其设计模式和代码风格。
    • 关联知识体系: 将新学的概念(如JavaFX的事件驱动、属性绑定)与已知的OOP原则(多态、观察者模式)联系起来,构建知识网络。

团队协作:沟通与规划是效率倍增器

  • 踩坑: 沟通不及时导致信息不同步、重复劳动;任务分配未考虑成员优势,造成忙闲不均和整体效率低下。

  • 领悟: 软件开发是团队运动,1+1能否大于2取决于协作效能。

  • 行动指南:

    • 建立高效沟通机制: 定期站立会议(同步进度、阻塞问题)、明确沟通渠道(IM群、邮件、文档)、使用协作工具(如GitHub Projects, Jira, Trello)。
    • 需求与变更透明化: 任何需求变更或关键设计决策,务必及时同步给所有相关成员。
    • 合理分工,发挥所长: 任务分配前评估成员技能、兴趣和负载。让擅长UI的做界面,逻辑强的写核心算法。任务粒度要适中且目标清晰。
    • 拥抱版本控制规范: (如Git Flow) 严格遵循分支管理、Commit Message规范、Code Review流程,避免代码冲突和混乱。
    • 定义清晰的接口契约: 模块间通过清晰的接口(Interface)定义交互方式,减少耦合,便于并行开发和集成。
      总结:
      这些“坑”并非学习的终点,而是能力跃升的跳板。它们让我深刻认识到:
  • 工匠精神: 编程不仅是实现功能,更是创造清晰、健壮、可维护的作品。代码规范和可读性是工匠精神的基本体现。

  • 工程思维: 软件开发需要系统的方法论。科学的调试、扎实的基础学习、有效的团队协作都是工程化思维不可或缺的部分。

  • 持续学习: 技术日新月异,唯有保持对原理的探究热情和良好的学习习惯,才能应对未来的挑战。踩过的每一个坑,都让我离成为一名合格的软件工程师更近一步。
    (四)、改进建议

  1. 在教学方面,希望老师在讲解知识点时,可以增加一些实际的项目案例,通过实际项目的演示和分析,让我们更加直观地理解抽象的概念和技术。同时,在课堂上可以增加一些互动环节,如小组讨论、提问解答等,提高同学们的参与度和学习积极性。此外,对于一些难度较大的知识点,老师可以提供更多的学习资源和辅导,帮助同学们更好地掌握。

  2. 在作业方面PTA 作业的题目可以更加多样化,除了现有的编程练习题外,可以增加一些算法设计和逻辑思维训练的题目,培养学生的创新能力和解决复杂问题的能力。同时,对于作业的难度分布,可以进行进一步的优化,避免出现题目难度起伏过大的情况。

  3. 在实验方面实验项目的选题可以更加贴近实际应用,增加一些具有商业价值和社会意义的项目,提高学生的学习兴趣和实践动力。在实验过程中,可以加强对学生的指导和监督,定期检查学生的实验进展情况,及时发现和解决学生遇到的问题。

posted @ 2025-06-22 14:57  念zzz  阅读(28)  评论(0)    收藏  举报