Java面向对象课程总结

课程总结性blog

前言

本课程采用​​多维度、阶梯式​​的教学框架,通过精心设计的五个核心环节(PTA编程作业、实验任务、Blog技术总结、线上视频课程和线下课堂教学)构建了完整的面向对象能力培养体系。经过一学期的系统学习,我对各环节的工作量和难度形成了清晰认知。同时通过学习不断得增强了自己利用编程解决问题得能力。锻炼了自己的思维。我对Java面向对象技术的核心思想与实践方法实现了从语法认知到系统设计的跃迁。本课程以​​“对象协作建模”​​ 为主线,通过阶梯式任务设计,逐步引导我们掌握封装、继承、多态等核心机制,并最终完成GUI应用开发的全流程实践。以下对各环节的工作量与难度进行概括性总结。

  • 线上课程:
    通过学堂在线平台完成12章核心知识点学习,内容覆盖Java基础语法到高级特性。
  • 线下课程:
    每周2次课,重点解析难点(如多态、异常处理)并穿插课堂小练习,强化代码实战能力。
  • PTA作业:
    共11次编程题,难度梯度明显,从基础语法到复杂算法再到面向对象设计逐步递进,平均每次作业耗时4-8小时。
  • 实验项目:
    5次实验(类设计、图形界面开发),需独立完成需求分析、代码编写与测试,总耗时约40小时。
  • Blog总结:
    通过技术博客记录学习过程,培养技术文档撰写能力。

总体感受:

课程设计注重“从理论到实践”的闭环,但部分知识点(如抽象类与接口的深层区别)需反复推敲才能掌握。以下从技术总结、踩坑心得、改进建议三方面展开详细分析。

一、面向对象技术总结:从入门到实践的认知升级

本部分结合PTA作业与实验项目,重点分析对封装、继承、多态、抽象类、接口、集合框架、异常处理及JavaFX等核心技术的掌握情况。

封装(Encapsulation)

学习成果:

理解封装的核心思想(数据隐藏与访问控制),通过private字段和public方法实现类内部逻辑的隔离。
封装是面向对象编程的重要特性之一,它通过将数据和操作数据的方法绑定在一起,并隐藏对象的内部实现细节,只对外提供必要的接口。在PTA作业和实验中,我深刻体会到了封装的重要性。通过封装,我学会了如何合理地组织代码,将相关的数据和方法组合在一起,提高代码的复用性。

示例

image

点击查看代码
public class Circle {
    private Coordinate coordinate;
    private double radius;

    public Circle(Coordinate coordinate, double radius) {
        this.coordinate = coordinate;
        this.radius = radius;
    }

    public Circle() {
    }

    public Coordinate getCoordinate() {
        return coordinate;
    }

    public void setCoordinate(Coordinate coordinate) {
        this.coordinate = coordinate;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }
}

将各个图形包装成类,满足封装原则。

认知提升:

封装不仅是语法规则,更是代码可维护性的保障。例如,通过set()方法添加输入校验逻辑,防止非法(如负数)被写入。

欠缺点:

对封装与性能优化的平衡理解不足。例如,在高频调用的方法中,过度封装可能导致额外开销(如频繁调用getter/setter)。

继承(Inheritance)与多态(Polymorphism)

学习成果:

掌握继承的语法(extends)与多态的实现方式(方法重写、向上转型)。
继承允许我们创建一个新的类(子类)来继承现有类(父类)的属性和方法,从而实现代码的复用和扩展。在课程中,我通过多个实例掌握了继承的使用方法。比如,在开发一个图形绘制程序时,我定义了一个Shape类作为父类,包含了图形的基本属性和方法,如颜色、位置等。然后,我创建了Circle、Rectangle等子类,继承自Shape类,并添加了各自特有的属性和方法,如半径、边长等。通过继承,我能够快速地创建出具有相似功能的类,减少了代码的重复编写,提高了开发效率。同时,我也理解了继承中的方法重写(Override)概念,子类可以根据需要对父类的方法进行重新实现。

示例

来源于pta作业的示例:

点击查看代码
public  abstract class  Shape {
    private String shapeName;

    public Shape(String shapeName) {
        this.shapeName = shapeName;
    }

    public Shape() {
    }

    public String getShapeName() {
        return shapeName;
    }

    public void setShapeName(String shapeName) {
        this.shapeName = shapeName;
    }
    public abstract  double getArea();
    public abstract boolean validate();
    public abstract  String toString();

}
public  class Trapezoid extends Shape{
    private double topSide;
    private double bottomSide;
    private double height;

    public Trapezoid(double topSide, double bottomSide, double height) {
        super("Trapezoid");
        this.topSide = topSide;
        this.bottomSide = bottomSide;
        this.height = height;
    }

    public Trapezoid() {
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public double getBottomSide() {
        return bottomSide;
    }

    public void setBottomSide(double bottomSide) {
        this.bottomSide = bottomSide;
    }

    public double getTopSide() {
        return topSide;
    }

    public void setTopSide(double topSide) {
        this.topSide = topSide;
    }
    public double getArea(){
        return (topSide+bottomSide)*height*0.5;
    }
    public String toString(){
        return getShapeName();

    }
    public boolean validate(){
        if(bottomSide<=0||topSide<=0||height<=0){
            return false;
        }
        else{
            return true;
        }
    }
}
体现多态:

private static Card createCardByType(int type) {
switch (type) {
case 1: // 圆形:半径
double radius = input.nextDouble();
if (radius <= 0) throw new IllegalArgumentException();
return new Card(new Circle(radius));
case 2: // 矩形:宽和长
double width = input.nextDouble();
double length = input.nextDouble();
if (width <= 0 || length <= 0) throw new IllegalArgumentException();
return new Card(new Rectangle(width, length));
case 3: // 三角形:三条边长
double a = input.nextDouble();
double b = input.nextDouble();
double c = input.nextDouble();
if (a <= 0 || b <= 0 || c <= 0 ) {
throw new IllegalArgumentException();
}
return new Card(new Triangle(a, b, c));
case 4: // 梯形:上底、下底、高
double top = input.nextDouble();
double bottom = input.nextDouble();
double height = input.nextDouble();
Triangle triangle = new Triangle(top,bottom,height);
if(top<=0||bottom<=0||height<=0){
throw new IllegalArgumentException();
}
return new Card(new Trapezoid(top, bottom, height));
default:
throw new IllegalArgumentException();
}

认知提升:

多态的核心是“同一接口,不同实现”。例如,通过父类引用调用子类重写的方法,实现代码的灵活扩展。

欠缺点:

对继承的滥用风险认识不足。例如,在PTA作业中曾因过度继承导致代码耦合度过高,后续通过组合(Composition)优化。

抽象类(Abstract Class)与接口(Interface)

学习成果:

理解抽象类与接口的语法差异(抽象类可包含具体方法,接口仅含抽象方法/默认方法)。
抽象类是一种不能被实例化的类,它通常用于定义一些通用的属性和方法,供子类继承和实现。在课程中,我学会了如何定义和使用抽象类。

认知提升:

抽象类适用于“is-a”关系(如Circle是Shape),接口适用于“can-do”关系(如Shape可以Draw)。

示例

点击查看代码
public  abstract class  Shape {
    private String shapeName;

    public Shape(String shapeName) {
        this.shapeName = shapeName;
    }

    public Shape() {
    }

    public String getShapeName() {
        return shapeName;
    }

    public void setShapeName(String shapeName) {
        this.shapeName = shapeName;
    }
    public abstract  double getArea();
    public abstract boolean validate();
    public abstract  String toString();

}
public class Card implements  Comparable<Card> {
    private Shape shape;

    public Card(Shape shape) {
        this.shape = shape;
    }

    public Card() {
    }

    public Shape getShape() {
        return shape;
    }

    public void setShape(Shape shape) {
        this.shape = shape;
    }
    public int compareTo(Card o){
if(this.shape.getArea()-o.shape.getArea()>0){
    return -1;
}
else{
    return 1;
}
    }
    public String toString(){
        return shape.toString()+":"+String.format("%.2f",shape.getArea());
    }
}

欠缺点:

对Java 8后接口默认方法的实际场景应用不足,仅停留在理论层面。

集合框架(Collection Framework)

学习成果:

掌握List、Set、Map的核心特性与适用场景(如ArrayList动态扩容、HashSet去重、HashMap键值对存储)。
Java集合框架提供了一系列用于存储和操作对象的类和接口,如List、Set、Map等。在课程中,我通过实验和PTA作业熟练掌握了集合框架的使用。

示例

如pta上一道题,编写程序统计一个输入的Java源码中关键字(区分大小写)出现的次数。说明如下:

Java中共有53个关键字(自行百度)
从键盘输入一段源码,统计这段源码中出现的关键字的数量
注释中出现的关键字不用统计
字符串中出现的关键字不用统计
统计出的关键字及数量按照关键字升序进行排序输出
未输入源码则认为输入非法
输入格式:
输入Java源码字符串,可以一行或多行,以exit行作为结束标志

输出格式:
当未输入源码时,程序输出Wrong Format
当没有统计数据时,输出为空
当有统计数据时,关键字按照升序排列,每行输出一个关键字及数量,格式为数量\t关键字

给出示例代码:

点击查看代码
import java.util.*;

public class Main {

    private static final String[] KEYWORDS = {
            "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const",
            "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float",
            "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
            "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp",
            "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void",
            "volatile", "while", "true", "false", "null"
    };
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder input = new StringBuilder();

        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            if ("exit".equals(line)) break;
            input.append(line).append('\n');
        }

        if (input.length() == 0) {
            System.out.println("Wrong Format");
            return;
        }

        String co = input.toString();
        Map<String, Integer> keywordCounts = new TreeMap<>();
        int state = 0;
        StringBuilder word = new StringBuilder();

        for (int i = 0; i < co.length(); i++) {
            char c = co.charAt(i);
            switch (state){
                case 0: // Normal code
                    if (c == '/' && i <co.length() - 1) {
                        char next=co.charAt(i + 1);
                        if (next=='/'){
                            state = 1; i++;
                        }
                        else if(next =='*') {
                            state = 2; i++;
                        }
                        else word.append(c);
                    }
                    else if (c == '"')
                        state = 3;
                    else if (c == '\'')
                        state = 4;
                    else if (Character.isLetter(c))
                        word.append(c);
                    else
                        processWord(word, keywordCounts);

                    break;

                case 1:
                    if (c == '\n') {
                        state = 0;
                        processWord(word, keywordCounts);
                    }
                    break;

                case 2:
                    if (c == '*' && i < co.length() - 1 && co.charAt(i + 1) == '/') {
                        state = 0;
                        i++;
                    }
                    break;

                case 3:
                    if (c=='"'&& (i == 0 || co.charAt(i - 1) != '\\')) state = 0;
                    break;

                case 4:
                    if (c == '\'' && (i == 0 || co.charAt(i - 1) != '\\')) state = 0;
                    break;
            }
        }
        processWord(word, keywordCounts);


        for (Map.Entry<String, Integer> entry : keywordCounts.entrySet()) {
            System.out.println(entry.getValue() + "\t" + entry.getKey());
        }
    }

    private static void processWord(StringBuilder word, Map<String, Integer> counts) {
        if (word.length() > 0) {
            String w = word.toString();
            if (isKeyword(w)) {
                counts.put(w, counts.getOrDefault(w, 0) + 1);
            }
            word.setLength(0);
        }
    }


    private static boolean isKeyword(String word) {
        for (String keyword : KEYWORDS) {
            if (keyword.equals(word)) {
                return true;
            }
        }
        return false;
    }
}

这道题主要是用到了集合框架和正则表达式来解答,考察我们对于map,set和list的理解和对正则表达式的认识。

认知提升:

集合框架是Java高效处理数据的基石。例如,Stream API结合集合可实现函数式编程(如filter()、map())。

欠缺点:

对并发集合(如ConcurrentHashMap)的理解仅停留在理论,未在项目中实践。

异常处理(Exception Handling)

学习成果:

掌握try-catch-finally语法与自定义异常类的编写。
在实验项目中,通过异常处理捕获用户输入错误(如非数字输入),提升程序健壮性。
异常处理是Java编程中不可或缺的一部分,它能够帮助我们处理程序运行过程中可能出现的错误和异常情况。在课程中,我学会了如何使用try-catch-finally语句块来捕获和处理异常。例如,在读取文件时,可能会遇到文件不存在或读取权限不足等异常情况,通过异常处理机制,我能够在程序出现异常时给出相应的提示信息,并保证程序的正常运行。同时,我也了解了自定义异常的使用方法,能够根据实际需求定义自己的异常类,提高代码的可读性和可维护性。

认知提升:

异常处理的核心是“将错误隔离在局部,避免程序崩溃”。例如,通过throws声明方法可能抛出的异常,明确调用方的责任。

欠缺点:

对异常链(Exception Chaining)的应用不足,未充分利用initCause()方法追踪异常根源。

JavaFX图形界面开发

学习成果:

掌握FXML布局与控制器分离的设计模式,通过Scene Builder快速构建界面。
在实验2中,实现登录窗口与主界面的动态切换,并通过事件监听器处理用户交互。
节点(Node):JavaFX 中所有可视化元素的基类(如按钮、文本框等)。
常用组件:
Button:按钮,用于触发事件。
Label:静态文本标签。
TextField/TextArea:单行/多行文本输入框。
ImageView:显示图片。
布局容器:
VBox/HBox:垂直/水平排列子节点。
BorderPane:分区域布局(上、下、左、右、中)。
GridPane:网格布局,适合表单类界面。
Stage stage = new Stage(); Scene scene = new Scene(new VBox(new Button("Hello")), 400, 300); stage.setScene(scene); stage.show();

认知提升:

JavaFX的MVC架构(Model-View-Controller)可有效分离业务逻辑与界面展示。

欠缺点:

对复杂动画效果(如Timeline类)的实现能力不足,仅完成基础交互功能。

二、采坑心得:从错误中成长的经验总结

本部分总结课程学习中的典型问题及解决方案,为后续学习提供参考。

  1. 继承与组合的误用
    问题描述:
    在实验1中,为复用代码,曾让父类继承Student类,导致父类被迫继承无关属性(如studentId)。
    解决方案:
    通过组合(Student作为Teacher的成员变量)替代继承,实现“has-a”关系。
    教训:
    优先使用组合而非继承,避免因过度继承导致代码僵化。
  2. 接口与抽象类的混淆
    问题描述:
    在实验3中,试图通过抽象类Shape实现多接口功能(如Drawable和Serializable),导致类结构臃肿。
    解决方案:
    将Drawable和Serializable拆分为接口,通过多接口实现功能扩展。
    教训:
    接口用于定义行为契约,抽象类用于共享代码实现,二者不可相互替代。
  3. 异常处理的过度捕获
    问题描述:
    在PTA作业中,为避免程序崩溃,曾捕获所有异常(catch (Exception e)),导致隐藏了潜在错误。
    解决方案:
    细化异常类型(如NumberFormatException、IOException),并针对性处理。
    教训:
    异常处理应“精准打击”,避免“一网打尽”。

三、改进建议及总结:对课程与教学的优化思考

本部分从课程设计、作业难度、实验指导等方面提出改进建议。

1. 对课程的改进建议

增加代码审查环节:
在实验提交后,安排小组互审或教师抽查代码,强化代码规范意识(如命名规则、注释标准)。
优化实验文档:
实验需求文档需更明确(如输入输出格式、边界条件),减少学生因理解偏差导致的返工。

2. 对教师的改进建议

加强课堂互动:
提供差异化指导:
针对基础薄弱的学生,开设课后答疑专场;针对学有余力的学生,推荐开源项目或竞赛资源。
分享行业经验:
邀请企业工程师分享Java在真实项目中的应用场景(如微服务架构、性能优化)。

3. 对作业与实验的改进建议

PTA作业分层设计:
将作业分为“基础题”“进阶题”“挑战题”,满足不同水平学生的需求。
实验项目模块化:
将大型实验拆分为多个小任务,并提供阶段性检查点,降低开发难度。
增加测试用例:
在PTA和实验中提供更全面的测试用例,帮助学生覆盖边界条件。

4. 对课下组织的改进建议

建立学习小组:
鼓励学生自发组队,通过GitHub协作开发,培养团队协作能力。
开设技术讲座:
定期邀请学长学姐分享Java学习经验(如算法竞赛、开源贡献)。
完善资源库:
整理课程相关文档(如API速查表、常见错误解决方案),供学生随时查阅。

四、总结:从技术到思维的全面成长

通过本课程的学习,我完成了从“面向过程”到“面向对象”的思维转变,掌握了封装、继承、多态等核心特性,并能够独立开发小型Java应用。课程中的PTA作业与实验项目锻炼了我的编码能力与问题解决能力,而踩坑经历则让我深刻理解了“代码质量”的重要性。

未来计划:

学习java设计模式
学习java框架
深入学习Java高级特性(如反射、注解、并发编程)。
参与开源项目,积累实战经验。

最后寄语:

面向对象编程不仅是技术,更是一种思维方式。愿我们都能在代码的世界中,用对象构建逻辑,用设计诠释优雅。

posted @ 2025-06-18 11:05  太妙了  阅读(60)  评论(0)    收藏  举报