第三次Blog作业:Java的课程总结

一、前言

本学期的Java课程即将结束,在这一学期的学习旅程中,我收获颇丰。从 Blog 作业记录学习心得,到 PTA 平台上不断攻克编程难题;从实验室里的实践操作,再到线上线下课程的知识汲取,每一项学习任务都像是一块块基石,搭建起我对这门学科的认知大厦。回顾这段学习历程,各项学习任务在工作量与难度上各有特点,层层递进。

① Blog作业:第一次Blog作业是对电梯调度题目集的总结,第二次Blog作业是对航空货运管理系统题目集的总结,这次是对整个课程的总结。这几次的Blog作业贯穿整个课程的学习,要求我们定期对所学知识进行梳理、总结,并分享自己的理解与感悟。在这个过程中,不仅锻炼了我的文字表达能力,更促使我深入思考课程内容,对所遇到的困难和不足进行反思,对知识点的把握有了更深的理解。而这几次的Blog是对完成的题目进行反思和总结,要对这一阶段的学习资料进行查找,工作量和难度都不太大。

②PTA作业:侧重于对编程实践能力的提升与考验。每一次作业都围绕课程中的核心知识点展开,题目数量较多,涵盖了从基础语法到复杂工程问题的各种题型,工作量不容小觑。除了一开始的对电梯调度的逻辑分析难度很大以外,其余的作业难度适中,都能够成功做出来。而且PTA采取了迭代的方式,通过对题目的理解和逐步破解,我的编程能力得到了显著提升,认识题目的角度也更加完善,逻辑思维也更加严谨。

③实验:实验环节是将理论知识转化为实际应用的关键途径。从实验环境的搭建,到按照实验步骤进行设计编写思路、编写相应的代码、分析实验结果,整个过程不仅要求我们熟悉理论知识,还考验我们的动手能力和解决实际问题的能力。实验的工作量较大,尤其是在遇到问题需要反复排查和调试时,更是耗时耗力。但是总体难度不大,都是对平常知识的巩固与实践。在这个过程中我学会了如何在实践中发现问题、分析问题并解决问题,加深了我对课程知识的理解和掌握。

④线上及线下课程:本门课程采取了线上和线下相结合的方式,方式新颖,配合得当。线上课程具有丰富的学习资源,没有时间限制,且讲了很多线下没讲的内容,值得我们反复观看与学习。线下老师跳脱传统讲课方式,采用生动形象的例子,帮助我们很好的理解与吸收知识,且讲述了很多书上没有的内容,例如Java的设计模式,让我们对相应的编程思想有了初步的把握。

总的来说,这门课程的各项学习任务相辅相成,让我充分的掌握了Java学习的面向对象编程思想以及几大设计原则的灵活运用,还培养了自主学习、独立思考和解决问题的能力。这些收获不仅可以运用到我的学业上,也对我的生活产生了潜移默化的积极影响

 

二、面向对象技术总结

1.封装

封装是面向对象编程的核心原则之一,它将数据(属性)和操作数据的方法绑定在一起,并通过访问修饰符(如private、protected、public)控制外部对这些成员的访问。封装的主要目的是隐藏内部实现细节,提供统一的公共接口,增强代码的安全性和可维护性。例如,在一次PTA雨刷程序功能扩展设计的题目里,要求程序能够根据雨刷系统的类型自动匹配其业务逻辑,两种系统的最大档位不同,因此我设计了一个private的maxPos属性,在不同的系统里通过对其的getter,setter可以设计想要的最大档位。

abstract class Calculate{
    private int pos;//档位
    private int maxPos;//最大档位

    public Calculate(){
        
    }
    
    public Calculate(int pos,int maxPos){
         this.pos = pos;
         this.maxPos = maxPos;
    }

     public int getPos(){
        return pos; 
    } 

    public int getMaxPos(){
        return maxPos;
    }

    public void Up(){
        if(this.pos < maxPos){
            this.pos ++;
        }
    }
    
    public void Down(){
        if(this.pos > 1){
            this.pos --;
        }
    } 


}
雨刷程序功能扩展里的封装

这让我学习到了如何灵活的运用封装保证数据的安全性和扩展,以及后续对数据进行校验和逻辑处理。

2.继承

继承允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用和层次化设计。在 Java 中,使用extends关键字实现继承,且每个类只能直接继承一个父(单继承),但可以通过接口实现多重继承的效果。例如,PTA航空货运管理系统里,要求输入客户、收件人和发件人的姓名、电话 、地址,于是我抽出一个人物类,用来封装姓名、电话、地址这些个人通用信息,作为Customer、Sender、Receiver类的父类。

 通过学习,我能够充分理解继承的特性,在代码复用,代码重写以及IS-A 关系里运用继承,通过创建子类继承父类的属性和方法,减少了大量重复代码的编写,提高了开发效率。在设计具有层次关系的程序结构时,继承能帮助我建立清晰的类层次体系,体现 “is-a” 的关系,使代码逻辑更加直观易懂。

3.多态

多态是同一操作作用于不同对象可以有不同的解释,产生不同的执行结果。多态允许不同类的对象通过相同的接口进行调用,从而实现 "一个接口,多种实现",以通过继承、接口和方法重写实现。例如,在实验三中将大象、老虎、狮子装进电器里,我用父类的Animal 引用指向不同的子类通过调用animal.enterElectric()时会根据实际对象类型执行不同的实现

// 抽象的动物类
abstract class Animal{
    
    private String name;
    private double weight;
    private int enterOrder;
    private int attackStrength;   
        // 动物类型,默认值为“动物”
    public String type = "动物";
    
    public Animal(){
        
    }
    
    public Animal(String name, double weight, int enterOrder,  int attackStrength){
        
        this.name = name;
        this.weight = weight;
        this.enterOrder = enterOrder;
        this.attackStrength = attackStrength;
        
    }
    
    public String getName(){
        
        return name;
        
    }
    
    public void setName(String name){
        
        this.name = name;
        
    }
    
    public double getWeight(){
        
        return weight;
        
    }
    
    public void setWeight(double weight){
        
        this.weight = weight;
        
    }
    
    public int getEnterOrder(){
        
        return enterOrder;
        
    }
    
    public void setEnterOrder(int enterOrder){
        
        this.enterOrder = enterOrder;
        
    }
    
    public int getAttackStrength(){
        
        return attackStrength;
        
    }
    
    public void setAttackStrength(int attackStrength){
        
        this.attackStrength = attackStrength;
        
    }
     
        // 抽象方法:动物进入电器
    public abstract void enterElectric(Electric electric);
    
}
// 大象类,继承自动物类
class Elephant extends Animal{
    
    public String type = "大象";
    
    public Elephant(String name,double weight, int enterOrder, int attackStrength){
        
        super(name, weight, enterOrder, attackStrength);
        
    }
    //可以运用多态让大象装进冰箱
    @Override
    public void enterElectric(Electric electric){
        electric.Open();
        int countBefore = electric.getAnimalCount();
        electric.addAnimal(this);
        int countAfter = electric.getAnimalCount();
        if(countAfter > countBefore){
            System.out.println(getName() + "进入了" + electric.getName() );
        }else{
            System.out.println(getName() + "没进入" + electric.getName() );
           }
    }
    

 }
public class Test{
    
    public static void main(String[] args) throws IOException{
        
        File file = new File("input.txt");
        
        int counts = 0;
        
        Scanner sc = new Scanner(file);
        
        System.out.println("请输入冰箱的名字和容量");
        String name = sc.next();
        int cap = sc.nextInt();
        counts += cap;
    IceBox iceBox = new IceBox(name, cap,false);//创建冰箱对象,初始状态为关闭

        
        System.out.println("请输入微波炉的名字和容量");
        name = sc.next();
        cap = sc.nextInt();
        counts += cap;
                 // 创建微波炉对象,初始状态为关闭
        Microwave microwave = new Microwave(name, cap,false);
        
        System.out.println("请输入洗衣机的名字和容量");
        name = sc.next();
        cap = sc.nextInt();
        counts += cap;
                 // 创建洗衣机对象,初始状态为关闭
        Washer washing = new Washer(name, cap,false);
        
        for(int i = 0; i < counts; i++){
            
            Animal animal = null;
            
                       // 生成0到2之间的随机数,用于选择动物类型
            int r = (int) ((float) Math.random() * 3);

                    // 生成0到1999之间的随机数,作为动物体重
            int w = (int) ((float) Math.random() *2000);
            
            switch(r){
                
                case 0:
                    animal = new Elephant("大象" + i, w, i, 0);
                    break;
                case 1:
                    animal = new Lion("狮子" + i, w, i, 1);
                    break;
                case 2:
                    animal = new Tiger("老虎" + i, w, i, 1);
                    break;
                    
                }
                
                if (animal == null)
                    continue;
                // 再次生成0到2之间的随机数,用于选择电器    
                r = (int) ((float) Math.random() *3);
                
                switch(r){
                    case 0:
                                                //运用多态装入电器
                        animal.enterElectric(iceBox);
                        break;
                        
                    case 1:
                        animal.enterElectric(washing);
                        break;
                        
                    case 2:
                        animal.enterElectric(microwave);
                        break;
                        
                    }
                    
                }
                
                Sort sort = new Sort();
                iceBox.sortShow(sort);
                washing.sortShow(sort);
                microwave.sortShow(sort);
                
            }
            
    }                    
多态的运用示例

这让我学习到了在程序需求发生变化,需要新增或修改功能时,无需大幅改动原有代码,只需创建新的子类并实现相关方法即可,让我理解如何编写更灵活、可扩展的代码,使程序具有良好的可维护性和扩展性。

4.抽象类

抽象类是不能被直接实例化的类,它主要作为其他类的基类,提供公共接口和部分实现。抽象类使用abstract关键字声明,可以包含抽象方法(无实现)和具体方法(有实现)。子类必须实现所有抽象方法才能被实例化。例如,在PTA图形卡片排序游戏里,把Shape设计为抽象类,包含计算面积和判断数据是否符合要求的抽象方法,让不同形状的子根据自身图形的特点,实现相应的面积计算和合法性验证逻辑。

//抽象类Shape
abstract class Shape{
    private String shapeName;
    // 构造方法等其他具体方法

    public abstract double getArea();

    public abstract boolean validate();

    @Override
    public String toString(){
        return shapeName;
    }
}
//梯形子类
class Trapezoid extends Shape{
    private double topSide;
    private double bottomSide;
    private double height;

    // 构造方法和属性访问方法

    @Override
    public double getArea(){
        return (topSide + bottomSide) * height / 2;
    }

    @Override
    public boolean validate(){
        if(topSide <= 0 || bottomSide <= 0 || height <= 0){
            return false;
        }
        return true;
    }
}
图形卡片排序游戏里的抽象类实现

这让我学会了抽象建模和规范制定。抽象类作为一种模板,定义了子类必须实现的方法,为子类提供了统一的行为规范。在实际开发中,我可以利用抽象类将具有共性的行为抽象出来,确保代码的一致性和规范性。

5.接口

接口是一种完全抽象的类型,它只包含常量和抽象方法的定义,不包含方法实现。类通过implements关键字实现接口,一个类可以实现多个接口,从而弥补单继承的限制。例如,实验四中,定义一个接口“有攻击性“:有一个方法返回0或1,表示该动物是否具有攻击性。

//攻击性接口        
interface Aggressive{
    
    int getAttackStyle();
    
}        
// 动物抽象类,实现Comparable和Aggressive接口    
abstract class Animal implements Comparable<Animal>, Aggressive {
    
    private String name;
    private double weight;
    private int enterOrder;
    private int attackStrength;
    private ArrayList<Animal> eatenAnimals = new ArrayList<> ();
    
    
    public Animal(){
        
    }
    
    public Animal(String name, double weight, int enterOrder,int attackStrength){
        
        this.name = name;
        this.weight = weight;
        this.enterOrder = enterOrder;
        this.attackStrength = attackStrength;
        
    }
    
    
    public String getName(){
        
        return name;
        
    }
    
    public void setName(String name){
        
        this.name = name;
        
    }
    
    public double getWeight(){
        
        return weight;
        
    }
    
    public void setWeight(double weight){
        
        this.weight = weight;
        
    }
    
    public int getEnterOrder(){
        
        return enterOrder;
        
    }
    
    public void setEnterOrder(int enterOrder){
        
        this.enterOrder = enterOrder;
        
    }
    
    public int getAttackStrength(){
        
        return attackStrength;
        
    }
    
    public void setAttackStrength(int attackStrength){
        
        this.attackStrength = attackStrength;
        
    }
        
    public ArrayList<Animal> getEatenAnimals() {
        
        return eatenAnimals;
        
    }
        //实现攻击性接口,默认实现返回0
    @Override
    public int getAttackStyle(){
        
        return 0;
        
    }
    
        //其他方法
        
    }

 //大象类,继承自Animal类
class Elephant extends Animal{
    
    public Elephant(){
        
    }
    
    public Elephant(String name, double weight, int enterOrder, int attackStrength){
        
        super(name, weight, enterOrder, attackStrength);
        
    }
    
    // 大象攻击方式为非攻击型
    @Override
    public int getAttackStyle(){
        
        return 0;
        
    }
    
        //继承的其他方法
    
}
实验四里的接口示例
这让我深入理解了解耦设计的重要性。通过类实现接口的方式,实现了不同类之间的功能统一,降低了类与类之间的耦合度,使程序各模块之间的依赖关系更加松散,便于独立开发、测试和维护。此外,Java 通过接口实现了类似多重继承的效果,突破了单继承的限制,让我在设计程序时能够更加灵活地组合不同的功能,提升了代码的复用性和可扩展性。

 6.集合框架

集合框架提供了一套用于存储和操作数据的接口和类,整个框架围绕几个核心接口构建:List(有序可重复集合,如ArrayList、LinkedList)、Set(无序唯一集合,如HashSet、TreeSet)、Queue(队列,如PriorityQueue)和Map(键值对映射,如HashMap、TreeMap)。其中,ArrayList基于动态数组实现,适合随机访问;LinkedList基于双向链表,适合频繁插入删除;HashMap提供平均O(1)时间复杂度的查找操作。集合框架还包含实用工具类Collections,提供排序、查找、同步化等各种算法操作。例如,在PTA图形卡片分组游戏里,定义了总的卡片集合,以及不同形状的卡片集合,用来对卡片里的数据进行存储和排序。

class DealCardList{

    //总的卡片集合
    private ArrayList<Card> cardList = new ArrayList<Card>();
    //圆形卡片集合
    private ArrayList<Card> CircleList = new ArrayList<Card>();
    //矩形卡片集合
    private ArrayList<Card> RectangleList = new ArrayList<Card>();
    //三角形卡片集合
    private ArrayList<Card> TriangleList = new ArrayList<Card>();
    //梯形卡片集合
    private ArrayList<Card> TrapezoidList = new ArrayList<Card>();
    

    public DealCardList(){
        
    }

    public DealCardList(ArrayList<Integer> list){
        Scanner sc = Main.input; // 使用Main中的静态Scanner
        for(int i = 0; i < list.size(); i++) {
            int shapeType = list.get(i);
            Shape shape = null;
            switch(shapeType){
                case 1:
                    double radius = sc.nextDouble();
                    shape = new Circle(radius);
                    CircleList.add(new Card(shape));
                    break;
                case 2:
                    double width = sc.nextDouble();
                    double length = sc.nextDouble();
                    shape = new Rectangle(width, length);
                    RectangleList.add(new Card(shape));
                    break;
                case 3:
                    double side1 = sc.nextDouble();
                    double side2 = sc.nextDouble();
                    double side3 = sc.nextDouble();
                    shape = new Triangle(side1, side2, side3);
                    TriangleList.add(new Card(shape));
                    break;
                case 4:
                    double topSide = sc.nextDouble();
                    double bottomSide = sc.nextDouble();
                    double height = sc.nextDouble();
                    shape = new Trapezoid(topSide, bottomSide, height);
                    TrapezoidList.add(new Card(shape));
                    break;

            }
            cardList.add(new Card(shape));
        }
    }

    public boolean validate(){
        for(int i = 0; i < cardList.size(); i++){
            Card card = cardList.get(i);
            if(!card.getShape().validate()){
                return false;
            }
        }
        return true;
    }

    //对不同种类的集合进行排序
    public void cardSort(ArrayList<Card> list){
        Collections.sort(list);
    }
    //求不同集合里的面积和
    public double getAllArea(ArrayList<Card> list){
        double sum = 0;
        for(int i = 0; i < list.size(); i++){
            Card card = list.get(i);
            sum += card.getShape().getArea();
        }

        return sum;
    }
    
    //其他方法
}     
图形卡片分组游戏里的集合框架示例

这让我学会了处理和存储数据的能力。集合框架提供了丰富的接口和类,适用于各种不同的数据存储和操作场景。从简单的列表、集合到复杂的映射结构,我学会了根据具体需求选择合适的集合类型,高效地进行数据的增删改查操作。但是,对于Set和Map接口,我还没有充分掌握,尽管知道有些场合使用这两个能更高效的解决问题,但因为缺乏熟练的运用,往往采取了另一种复杂的方法,今后我会加强对这几个接口的深入学习,做到简单高效的解决问题。

7.异常

异常是Java处理程序运行时错误的机制,分为检查型异常(如IOException,必须处理)和运行时异常(如NullPointerException,可选择性处理)。通过try-catch-finally结构,程序能捕获和处理异常,避免意外崩溃。例如,PTA统计Java程序中关键词的出现次数里,运用了异常处理机制,当未输入源码时,程序不会崩溃停止,而是捕获和处理错误。

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        
        //运用try-catch来捕获未输入源码时的异常情况
        try{

            sc.useDelimiter("\\Z");
            String longText = sc.next();

            if(longText.equals("exit") || longText.isEmpty()){
                System.out.println("Wrong Format");
            }else{
                ArrayList<String> list = new ArrayList<>();
                list.add("abstract");
                list.add("assert");
                list.add("boolean");
                list.add("break");
                list.add("byte");
                list.add("case");
                list.add("catch");
                list.add("char");
                list.add("class");
                list.add("continue");
                list.add("default");
                list.add("do");
                list.add("double");
                list.add("else");
                list.add("enum");
                list.add("extends");
                list.add("final");
                list.add("finally");
                list.add("float");
                list.add("for");
                list.add("if");
                list.add("implements");
                list.add("import");
                list.add("int");
                list.add("interface");
                list.add("instanceof");
                list.add("long");
                list.add("native");
                list.add("new");
                list.add("package");
                list.add("private");
                list.add("protected");
                list.add("public");
                list.add("return");
                list.add("short");
                list.add("static");
                list.add("strictfp");
                list.add("super");
                list.add("switch");
                list.add("synchronized");
                list.add("this");
                list.add("throw");
                list.add("throws");
                list.add("transient");
                list.add("try");
                list.add("void");
                list.add("volatile");
                list.add("while");
                list.add("goto");
                list.add("const");
                list.add("true");
                list.add("false");
                list.add("null");

                dealWith processor = new dealWith();
                processor.setList(list);

                ArrayList<String> newList1 = processor.check(longText);
                ArrayList<Integer> newList2 = processor.contain(longText, newList1);

                ArrayList<KeyWordCount> results = new ArrayList<>();
                for (int i = 0; i < newList1.size(); i++) {
                    results.add(new KeyWordCount(newList1.get(i), newList2.get(i)));
                }

                Collections.sort(results);

                for(int i = 0; i < results.size(); i++){
                    KeyWordCount result = results.get(i);
                    System.out.printf("%d\t%s\n", result.getCount(), result.getKeyWord());
                }
        
             }

        }catch (Exception e) {
            System.out.println("Wrong Format"); 
        }
    }
}
统计Java程序中关键词的出现次数里的异常处理示例

这让我学会了如何构建健壮可靠的程序。通过使用try-catch-finally语句块,我能够捕获和处理程序运行时可能出现的各种错误,避免程序因异常而崩溃,提高了程序的容错性和稳定性。

8.JavaFX

JavaFX 是 Java 的官方 GUI(图形用户界面)框架,用于构建跨平台的桌面和移动端应用程序,支持响应式布局和事件驱动编程。例如,第五次实验里,运用了Button、ListView 等组件搭建电器与动物选择界面,利用鼠标点击事件监听和 Lambda 表达式实现电器与动物的交互选择,用JavaFx简单做了一个把动物装进电器的可视化界面。

 这让我学会了图形界面开发的基本技能。从创建简单的窗口和控件,到使用布局管理器设计复杂的界面布局,我学会了运用 JavaFX 构建简单的用户界面。JavaFx的内容非常丰富,且这部分的学习通过翻转课堂实现的,对于一些复杂的内容没能完全掌握,需要进一步的了解和探索。

 

三、踩坑心得

弯路:

(1)电梯系统开发的重重困境
在电梯系统代码编写初期,由于对题目理解不透彻,我盲目地将多种电梯功能混杂实现,忽视了逻辑的合理性与代码的性能优化,最终导致程序运行超时。尽管在参考运行过程详解后,我修正了部分逻辑,但因过度依赖题目给定的测试用例,未能自主设计更多测试场景,使得程序在面对其他测试数据时依然出现答案错误的情况。此外,在后续题目迭代中,我又接连遭遇输出为空、电梯运行结果不符等问题,这些都源于对程序状态判断的疏忽以及请求处理逻辑的漏洞 。
 
(2)运费计算程序的细节疏漏
在设计运费计算程序时,我因思维局限,在输出格式和方法设计上陷入僵局,耗费大量时间才找到合适的解决方案。而在代码实现阶段,对细节的把控不足导致程序出现非零返回的异常,经排查发现是 switch 语句中遗漏break语句,致使支付方式判断逻辑错误。同时,代码中存在大量重复逻辑,显著增加了程序的复杂度和维护成本。
 
经验教训:
 
(1)前期准备与逻辑规划至关重要
两次实践经历均表明,急于编写代码而忽视前期规划是大忌。在拿到题目后,必须仔细研读需求,理清程序的运行逻辑,通过绘制类图、流程图等方式构建清晰的架构,避免功能混杂和逻辑混乱,为后续开发奠定坚实基础。
(2)测试用例设计需全面深入
不能仅仅满足于通过题目给定的测试用例,而应主动设计涵盖边界情况、异常输入、复杂场景等多种情况的测试数据,对程序进行全方位测试。这样才能及时发现潜在问题,确保代码的稳定性和正确性。
(3)代码质量与规范不容忽视
在代码编写过程中,要时刻遵循编程规范和设计原则。一方面,合理运用封装、继承、多态等面向对象特性,优化代码结构,减少重复代码;另一方面,严格控制方法复杂度,遵循单一职责原则,通过拆分复杂方法、简化嵌套逻辑等方式,提高代码的可读性和可维护性。同时,及时添加详细注释,清晰阐述代码功能和逻辑,方便自己和他人理解。
(4)细节决定成败
编程是一项需要高度严谨的工作,任何细微的疏漏都可能导致程序出错。在编写代码时,要对语法细节、逻辑判断、变量作用域等保持高度敏感,养成仔细检查和复盘的习惯,及时发现并修正潜在问题。
 
 
四、改进建议及总结

通过本学期的Java课程学习,我系统掌握了面向对象编程的核心思想与设计原则,包括封装、继承、多态三大特性,以及抽象类、接口、集合框架等关键技术。在实践过程中,我深刻体会到单一职责、开闭原则、里氏替换等设计原则的重要性,并学会了运用这些原则构建更健壮、可扩展的代码结构。课程通过Blog反思、PTA编程、实验操作等多元化的学习方式,培养了我的问题分析能力、编程实践能力和系统设计思维。特别是JavaFX的学习让我初步掌握了现代GUI开发技术,而异常处理机制则强化了我的防御性编程意识。建议未来课程可以适当增加实际案例的讲解,帮助更好地理解面向对象思想在复杂系统中的应用。总体而言,这门课程不仅让我掌握了Java编程技能,更重要的是培养了我用面向对象思维方式分析和解决问题的能力,为后续的软件开发学习奠定了坚实基础。

 

 

 

 

 

 

 

 
 
posted @ 2025-06-16 20:45  种自己的太阳  阅读(56)  评论(0)    收藏  举报