NCHU-OOP-第三次Blog作业-课程总结
NCHU-OOP-第三次Blog作业-课程总结
目录
前言
本学期的 Java 课程学习之旅即将结束,回顾这段学习历程,课程通过多种教学环节的有机结合,帮助我们逐步构建起扎实的 Java 知识体系。从 Blog 作业到 PTA 编程练习,从实验操作到线上线下课程学习,每一个环节都承载着不同的学习目标与挑战,其工作量和难度各有特点,却又相互关联、层层递进。
①.Blog 作业:贯穿整个学期,它要求我们对阶段性的学习内容进行梳理、总结与反思,不仅锻炼了我们的文字表达能力,更促使我们深入思考所学知识,将碎片化的内容系统化。每次完成 Blog 作业,都像是对学习成果的一次复盘,在回顾中加深对知识的理解。其工作量适中,难度在于如何清晰、有条理地阐述复杂的知识点,以及如何结合自身学习经历进行有深度的总结。
②.PTA 作业:则侧重于编程实践能力的培养,题目数量众多且难度逐步提升。从基础的语法运用到复杂的算法实现,每一道题目都需要我们运用所学知识进行分析、设计和编码。初期的题目主要帮助我们巩固基础知识,随着课程推进,题目涉及到更多面向对象的特性和复杂逻辑,对编程思维和代码编写能力提出了更高要求。大量的 PTA 作业虽然带来了一定的压力,但也让我们在不断的实践中提升了编程技能。
③实验环节:是理论知识与实际应用相结合的重要途径。通过完成一系列实验项目,我们能够将课堂上学习的概念转化为可运行的程序。实验内容涵盖了课程的核心知识点,从简单的类和对象的创建,到复杂的系统功能实现,需要我们综合运用多种技术。实验的难度较大,不仅要求我们对知识有深入的理解,还需要具备解决实际问题的能力,在遇到问题时能够通过调试、查阅资料等方式找到解决方案。
④线上线下课程:相互配合,为我们提供了全面的学习支持。线上课程为我们提供了丰富的学习资源,包括视频讲解、电子文档等,方便我们在课后进行自主学习和复习,可根据个人的学习进度进行灵活安排,有助于我们查漏补缺。线下课程则通过教师的面对面讲解、互动答疑和案例分析,让我们更直观地理解抽象的概念,同时也营造了良好的学习氛围,便于我们与同学交流学习心得 。
总体而言,这门课程的各个教学环节相辅相成,共同助力我们在 Java 学习道路上不断前进。虽然学习过程中充满挑战,但每一次克服困难、完成作业和实验,都让我们在 Java 编程能力和知识储备上有了显著的提升。
面向对象技术总结
封装
在 PTA 作业和实验中,封装的概念得到了充分的应用。通过将类的属性私有化,并提供公共的访问方法(getter 和 setter),实现了对数据的保护和控制。例如,在设计一个学生类时,将学生的成绩属性私有化,外部只能通过特定的方法获取和修改成绩,这样可以在方法中添加数据验证逻辑,确保成绩在合理的范围内。
学生成绩封装示例
// 封装示例
class Student {
// 私有属性,外部无法直接访问
private String name;
private int age;
private double score;
// 公共的getter方法,用于获取name属性
public String getName() {
return name;
}
// 公共的setter方法,用于设置name属性,包含数据验证
public void setName(String name) {
if (name == null || name.isEmpty()) {
System.out.println("姓名不能为空");
return;
}
this.name = name;
}
// 公共的getter方法,用于获取age属性
public int getAge() {
return age;
}
// 公共的setter方法,用于设置age属性,包含数据验证
public void setAge(int age) {
if (age < 0 || age > 150) {
System.out.println("年龄不合法");
return;
}
this.age = age;
}
// 公共的getter方法,用于获取score属性
public double getScore() {
return score;
}
// 公共的setter方法,用于设置score属性,包含数据验证
public void setScore(double score) {
if (score < 0 || score > 100) {
System.out.println("分数不合法");
return;
}
this.score = score;
}
// 重写toString方法,方便打印对象信息
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + ", score=" + score + "}";
}
}
public class EncapsulationExample {
public static void main(String[] args) {
Student student = new Student();
student.setName("张三");
student.setAge(20);
student.setScore(95.5);
System.out.println(student); // 输出:Student{name='张三', age=20, score=95.5}
// 尝试设置不合法的年龄
student.setAge(-5); // 输出:年龄不合法
System.out.println(student.getAge()); // 输出:20,年龄未被修改
}
}
在学习初期,对于封装的理解仅停留在语法层面,认为只是简单地将属性私有化。但随着不断实践,逐渐认识到封装的真正价值在于隐藏对象的内部实现细节,对外提供统一的接口,提高了代码的安全性和可维护性。目前,对于基本的封装操作已经能够熟练掌握,但在复杂业务场景下,如何合理地设计封装结构,以满足系统的扩展性和灵活性需求,还需要进一步学习和实践。
继承
继承是面向对象编程的重要特性之一,在课程学习中,通过 PTA 作业和实验中的类层次结构设计,深刻体会到了继承的优势。继承允许子类复用父类的属性和方法,减少了代码的重复。例如,设计一个图形类作为父类,包含通用的属性和方法,然后通过继承创建圆形类、矩形类等子类,子类只需添加自身特有的属性和方法即可。
图形面积示例
// 继承示例
// 父类:图形
class Shape {
protected String color;
protected double area;
public Shape(String color) {
this.color = color;
}
// 计算面积的方法,子类可以重写
public double calculateArea() {
return 0;
}
public String getColor() {
return color;
}
public double getArea() {
return area;
}
public void setArea(double area) {
this.area = area;
}
@Override
public String toString() {
return "Shape{color='" + color + "', area=" + area + "}";
}
}
// 子类:圆形,继承自Shape
class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color); // 调用父类的构造方法
this.radius = radius;
}
// 重写父类的计算面积方法
@Override
public double calculateArea() {
area = Math.PI * radius * radius;
return area;
}
public double getRadius() {
return radius;
}
@Override
public String toString() {
return "Circle{radius=" + radius + ", " + super.toString() + "}";
}
}
// 子类:矩形,继承自Shape
class Rectangle extends Shape {
private double width;
private double height;
public Rectangle(String color, double width, double height) {
super(color); // 调用父类的构造方法
this.width = width;
this.height = height;
}
// 重写父类的计算面积方法
@Override
public double calculateArea() {
area = width * height;
return area;
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
@Override
public String toString() {
return "Rectangle{width=" + width + ", height=" + height + ", " + super.toString() + "}";
}
}
public class InheritanceExample {
public static void main(String[] args) {
Circle circle = new Circle("红色", 5.0);
System.out.println("圆形面积: " + circle.calculateArea()); // 输出:圆形面积: 78.53981633974483
System.out.println(circle); // 输出:Circle{radius=5.0, Shape{color='红色', area=78.53981633974483}}
Rectangle rectangle = new Rectangle("蓝色", 4.0, 6.0);
System.out.println("矩形面积: " + rectangle.calculateArea()); // 输出:矩形面积: 24.0
System.out.println(rectangle); // 输出:Rectangle{width=4.0, height=6.0, Shape{color='蓝色', area=24.0}}
}
}
在实践过程中,遇到了方法重写的问题,需要确保子类重写的方法与父类方法的签名一致,同时要考虑到方法的多态性。 通过不断调试和总结,掌握了继承的基本使用方法和注意事项。然而,在处理复杂的继承关系,如多层继承和菱形继承问题时,还存在理解不够深入的情况,需要进一步研究相关的解决方案和设计模式。
多态
多态是面向对象编程的核心概念,在 PTA 作业和实验中,通过方法重写和接口实现展示了多态的特性。例如,在一个动物叫声的模拟程序中,定义一个动物接口,包含一个叫的方法,然后让猫类、狗类等实现该接口,并根据不同的实现类调用相应的叫的方法,实现了同一方法在不同对象上的不同表现。
动物叫声示例
// 多态示例
// 接口:动物
interface Animal {
void sound(); // 抽象方法,动物发出声音
}
// 实现类:猫
class Cat implements Animal {
@Override
public void sound() {
System.out.println("喵喵喵");
}
// 猫类特有的方法
public void scratch() {
System.out.println("猫抓东西");
}
}
// 实现类:狗
class Dog implements Animal {
@Override
public void sound() {
System.out.println("汪汪汪");
}
// 狗类特有的方法
public void fetch() {
System.out.println("狗捡东西");
}
}
// 实现类:鸟
class Bird implements Animal {
@Override
public void sound() {
System.out.println("叽叽喳喳");
}
// 鸟类特有的方法
public void fly() {
System.out.println("鸟飞翔");
}
}
public class PolymorphismExample {
public static void main(String[] args) {
// 使用接口类型引用不同的实现类对象
Animal cat = new Cat();
Animal dog = new Dog();
Animal bird = new Bird();
// 调用相同的方法,表现出不同的行为
cat.sound(); // 输出:喵喵喵
dog.sound(); // 输出:汪汪汪
bird.sound(); // 输出:叽叽喳喳
// 多态数组
Animal[] animals = {cat, dog, bird};
for (Animal animal : animals) {
animal.sound();
}
// 向下转型,需要先进行类型检查
if (cat instanceof Cat) {
Cat catObj = (Cat) cat;
catObj.scratch(); // 输出:猫抓东西
}
if (dog instanceof Dog) {
Dog dogObj = (Dog) dog;
dogObj.fetch(); // 输出:狗捡东西
}
if (bird instanceof Bird) {
Bird birdObj = (Bird) bird;
birdObj.fly(); // 输出:鸟飞翔
}
}
}
在学习过程中,理解了多态的实现方式和作用,它使得程序的扩展性和可维护性大大提高。当需要添加新的动物类时,只需要实现动物接口即可,而不需要修改调用方法的代码。在实际应用中,对于多态的灵活运用还不够熟练,特别是在复杂的业务逻辑中,如何准确地设计多态结构,以达到最佳的代码效果,还需要更多的实践和思考。
抽象类
抽象类在课程中主要用于定义一些具有共性但又无法具体实例化的类。在实验项目中,当设计一个具有多种具体实现的通用功能时,使用抽象类来定义规范和部分通用实现。例如,在设计一个交通工具抽象类,包含一些通用的属性和方法,如速度、行驶等,具体的交通工具类如汽车类、飞机类等继承该抽象类,并实现其抽象方法。
交通工具抽象类
// 抽象类示例
// 抽象类:交通工具
abstract class Vehicle {
protected String brand;
protected int year;
public Vehicle(String brand, int year) {
this.brand = brand;
this.year = year;
}
// 抽象方法:启动
public abstract void start();
// 抽象方法:停止
public abstract void stop();
// 具体方法:显示信息
public void showInfo() {
System.out.println("品牌: " + brand + ", 年份: " + year);
}
}
// 具体类:汽车,继承自Vehicle
class Car extends Vehicle {
private int numDoors;
public Car(String brand, int year, int numDoors) {
super(brand, year);
this.numDoors = numDoors;
}
@Override
public void start() {
System.out.println("汽车启动:插入钥匙,转动点火开关");
}
@Override
public void stop() {
System.out.println("汽车停止:踩刹车,挂P档,熄火");
}
public void showCarInfo() {
showInfo();
System.out.println("车门数: " + numDoors);
}
}
// 具体类:自行车,继承自Vehicle
class Bicycle extends Vehicle {
private int numGears;
public Bicycle(String brand, int year, int numGears) {
super(brand, year);
this.numGears = numGears;
}
@Override
public void start() {
System.out.println("自行车启动:踩踏板");
}
@Override
public void stop() {
System.out.println("自行车停止:捏刹车");
}
public void showBicycleInfo() {
showInfo();
System.out.println("齿轮数: " + numGears);
}
}
public class AbstractClassExample {
public static void main(String[] args) {
// 不能实例化抽象类,但可以使用抽象类的引用指向具体子类对象
// Vehicle vehicle = new Vehicle("奔驰", 2023); // 错误,不能实例化抽象类
Vehicle car = new Car("宝马", 2022, 4);
car.start(); // 输出:汽车启动:插入钥匙,转动点火开关
car.stop(); // 输出:汽车停止:踩刹车,挂P档,熄火
car.showInfo(); // 输出:品牌: 宝马, 年份: 2022
// 向下转型为Car类型
if (car instanceof Car) {
Car carObj = (Car) car;
carObj.showCarInfo(); // 输出:品牌: 宝马, 年份: 2022 车门数: 4
}
Vehicle bicycle = new Bicycle("捷安特", 2021, 18);
bicycle.start(); // 输出:自行车启动:踩踏板
bicycle.stop(); // 输出:自行车停止:捏刹车
bicycle.showInfo(); // 输出:品牌: 捷安特, 年份: 2021
// 向下转型为Bicycle类型
if (bicycle instanceof Bicycle) {
Bicycle bicycleObj = (Bicycle) bicycle;
bicycleObj.showBicycleInfo(); // 输出:品牌: 捷安特, 年份: 2021 齿轮数: 18
}
}
}
通过实践,理解了抽象类的作用是为子类提供一个统一的框架和规范,提高了代码的可扩展性和可维护性。但对于抽象类与接口的区别以及在不同场景下的选择使用,还需要进一步深入理解和分析。
接口
接口在课程学习中是实现多态和代码解耦的重要工具。在 PTA 作业和实验中,经常使用接口来定义一组规范,让不同的类实现该接口,以达到不同的功能实现。例如,在一个支付系统的设计中,定义一个支付接口,包含支付方法,然后让支付宝类、微信支付类等实现该接口,通过接口的多态性实现不同支付方式的调用。
接口示例
// 接口示例
// 接口:可绘制
interface Drawable {
void draw(); // 抽象方法:绘制
default void printInfo() { // 默认方法:打印信息
System.out.println("这是一个可绘制的对象");
}
static double getPi() { // 静态方法:获取圆周率
return Math.PI;
}
}
// 接口:可着色
interface Colorable {
void setColor(String color); // 抽象方法:设置颜色
String getColor(); // 抽象方法:获取颜色
}
// 实现类:圆形,实现Drawable和Colorable接口
class Circle implements Drawable, Colorable {
private double radius;
private String color;
public Circle(double radius, String color) {
this.radius = radius;
this.color = color;
}
@Override
public void draw() {
System.out.println("绘制一个半径为" + radius + "的圆形");
}
@Override
public void setColor(String color) {
this.color = color;
}
@Override
public String getColor() {
return color;
}
public double getArea() {
return Drawable.getPi() * radius * radius; // 调用接口的静态方法
}
}
// 实现类:矩形,实现Drawable和Colorable接口
class Rectangle implements Drawable, Colorable {
private double width;
private double height;
private String color;
public Rectangle(double width, double height, String color) {
this.width = width;
this.height = height;
this.color = color;
}
@Override
public void draw() {
System.out.println("绘制一个宽为" + width + ",高为" + height + "的矩形");
}
@Override
public void setColor(String color) {
this.color = color;
}
@Override
public String getColor() {
return color;
}
public double getArea() {
return width * height;
}
}
public class InterfaceExample {
public static void main(String[] args) {
Circle circle = new Circle(5.0, "红色");
circle.draw(); // 输出:绘制一个半径为5.0的圆形
System.out.println("圆形颜色: " + circle.getColor()); // 输出:圆形颜色: 红色
System.out.println("圆形面积: " + circle.getArea()); // 输出:圆形面积: 78.53981633974483
circle.printInfo(); // 输出:这是一个可绘制的对象
Rectangle rectangle = new Rectangle(4.0, 6.0, "蓝色");
rectangle.draw(); // 输出:绘制一个宽为4.0,高为6.0的矩形
System.out.println("矩形颜色: " + rectangle.getColor()); // 输出:矩形颜色: 蓝色
System.out.println("矩形面积: " + rectangle.getArea()); // 输出:矩形面积: 24.0
rectangle.printInfo(); // 输出:这是一个可绘制的对象
// 使用接口数组
Drawable[] drawables = {circle, rectangle};
for (Drawable drawable : drawables) {
drawable.draw();
if (drawable instanceof Colorable) {
Colorable colorable = (Colorable) drawable;
System.out.println("颜色: " + colorable.getColor());
}
drawable.printInfo();
}
}
}
通过不断的实践,掌握了接口的定义和实现方法,认识到接口能够使代码更加灵活和可扩展。但在接口的设计和使用过程中,对于接口的粒度把握不够准确,有时会出现接口定义过于宽泛或过于细化的问题,影响了代码的质量和可维护性。
集合框架
集合框架在课程学习中是处理大量数据的重要工具。在 PTA 作业和实验中,经常使用 List、Set、Map 等集合类来存储和操作数据。例如,在一个学生成绩管理系统中,使用 List 来存储学生对象,方便进行添加、删除和查询操作;使用 Map 来存储学生姓名和成绩的对应关系,便于快速查找。
通过实践,掌握了不同集合类的特点和使用场景,能够根据具体需求选择合适的集合类。但在集合的性能优化和复杂操作方面,如在大量数据下如何提高集合的查询效率,还需要进一步学习和研究相关的算法和数据结构知识。
异常
异常处理在课程中是保证程序稳定性和可靠性的重要机制。在 PTA 作业和实验中,通过捕获和处理各种异常,提高了程序的健壮性。例如,在读取文件或进行网络连接时,可能会出现各种异常情况,通过 try - catch 语句块来捕获异常,并进行相应的处理,避免程序因异常而崩溃。
⒈定义自定义异常类
class otherException extends Exception {
public otherException(String message) {
super(message);
}
}
⒉在方法签名中声明可能抛出的异常
public static int quote(int a, int b) throws otherException {
if(a == 0)
throw new otherException("被除数不能为0");
if(b == 0)
throw new ArithmeticException("除数不能为0");
if(a<0||b<0){
throw new ArithmeticException("数字大小不能小于0");
}
return a / b;
}
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
int b = sc.nextInt();
int c = quote(a, b);
System.out.println(c);
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
} catch (otherException e) {
System.out.println(e.getMessage());
} finally {
System.out.println("程序结束");
}//在finally块中,可以保证代码块中的代码一定执行
}
在学习过程中,掌握了常见异常的类型和处理方法,理解了异常处理的重要性。但在实际应用中,对于自定义异常的使用还不够熟练,特别是在复杂的业务逻辑中,如何合理地抛出和处理自定义异常,以提高程序的可读性和可维护性,还需要进一步学习和实践。
JavaFX
JavaFX 在实验项目中用于图形用户界面的设计和开发。通过学习和实践,掌握了 JavaFX 的基本控件使用,如按钮、文本框、标签等,以及布局管理器的应用,能够设计出简单的图形用户界面。例如,在一个简单的学生信息管理系统的界面设计中,使用 JavaFX 创建了包含输入框、按钮和表格的界面,实现了基本的用户交互功能。
但 JavaFX 的功能非常丰富,对于一些高级功能,如动画效果、自定义控件等,还处于初步了解阶段,需要进一步深入学习和探索,以满足更复杂的界面设计需求。
这是上次的ViewList的相关项目源码,字体部分还有问题,没办法读取,希望大佬多提一些意见_(:з」∠)_l,勿喷
package ListViewExample;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import java.time.LocalTime;
import java.util.Optional;
/**
* ListView示例应用程序,展示如何使用JavaFX创建带有ListView的GUI,
* 并实现主题切换和列表项操作等功能。
*/
public class ListViewExample extends Application {
// 定义字体名称和大小
private static final String FONT_NAME = "Minecraft.ttf";
private static final double FONT_SIZE = 12;
// 定义白天和夜晚模式的样式
private static final String STYLE_DAY = "-fx-background-color: #ffffff; -fx-text-fill: #000000;";
private static final String STYLE_NIGHT = "-fx-background-color: #1e1e1e; -fx-text-fill: #ffffff;";
// 带背景图的样式
private static final String STYLE_DAY_WITH_BG =
"-fx-background-image: url('file:///C:/Users/lenovo/Desktop/绘制艺术插.png');" +
"-fx-background-size: cover;"+
"-fx-effect: innershadow(gaussian, rgb(182,255,251), 10, 0, 0, 0);" +
"-fx-background-color: rgba(0, 0, 0, 0.0);"; // 暗化背景
// 带有特效的夜晚模式样式
private static final String STYLE_NIGHT_WITH_EFFECT =
"-fx-background-image: url('file:///C:/Users/lenovo/Desktop/绘制艺术插画.png');" +
"-fx-background-size: cover;" +
"-fx-effect: innershadow(gaussian, rgba(200,0,255,0.8), 10, 0, 0, 0);" +
"-fx-background-color: rgba(0, 0, 0, 0.6);"; // 暗化背景
// 创建一个ToggleGroup用于主题切换
private ToggleGroup themeToggleGroup = new ToggleGroup();
private boolean autoTheme = true;
@Override
public void start(Stage primaryStage) {
// 尝试加载Minecraft字体
loadMinecraftFont();
primaryStage.setTitle("List Design");
// 创建一个ObservableList来存储列表数据
ObservableList<String> items = FXCollections.observableArrayList(
"WELCOME", "TO", "NCHU", "!"
);
// 创建ListView并设置数据
ListView<String> listView = new ListView<>(items);
listView.setPrefSize(200, 150);
// 设置列表视图的字体
listView.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
// 设置多选模式
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// 添加选中项变化事件处理
listView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Selected Item: " + newValue);
});
// 创建按钮用于添加和删除项目
Button addButton = new Button("添加项目");
addButton.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
addButton.setOnAction(e -> {
int size = items.size();
items.add("New Item " + (size + 1));
});
Button removeButton = new Button("移除项目");
removeButton.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
removeButton.setOnAction(e -> {
ObservableList<Integer> selectedIndices = listView.getSelectionModel().getSelectedIndices();
for (int i = selectedIndices.size() - 1; i >= 0; i--) {
items.remove(selectedIndices.get(i).intValue());
}
});
// 改变item的名称并实现可视化修改
Button changeButton = new Button("更改项目名称");
changeButton.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
changeButton.setOnAction(e -> {
ObservableList<Integer> selectedIndices = listView.getSelectionModel().getSelectedIndices();
for (int i = 0; i < selectedIndices.size(); i++) {
int index = selectedIndices.get(i).intValue();
String currentItem = items.get(index);
TextInputDialog dialog = new TextInputDialog(currentItem);
dialog.setTitle("修改项");
dialog.setHeaderText("更改选中的项:");
dialog.setContentText("请输入新的名称:");
// 设置对话框字体
setDialogFont(dialog);
Optional<String> result = dialog.showAndWait();
result.ifPresent(newName -> {
if (!newName.trim().isEmpty()) {
items.set(index, newName);
}
});
}
});
// 创建菜单栏
MenuBar menuBar = new MenuBar();
menuBar.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
// 菜单项:项目总览、修改、自动排序
MenuItem overviewItem = new MenuItem("项目总览");
overviewItem.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
overviewItem.setOnAction(e -> showOverview(items));
MenuItem modifyItem = new MenuItem("修改");
modifyItem.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
modifyItem.setOnAction(e -> addNewItem(items));
MenuItem sortItem = new MenuItem("自动排序");
sortItem.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
sortItem.setOnAction(e -> items.sort(String::compareToIgnoreCase));
Menu operationMenu = new Menu("操作");
operationMenu.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
operationMenu.getItems().addAll(overviewItem, modifyItem, sortItem);
// 主题菜单
Menu themeMenu = new Menu("主题");
themeMenu.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
RadioMenuItem autoItem = new RadioMenuItem("自动切换(默认)");
autoItem.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
RadioMenuItem dayItem = new RadioMenuItem("白天模式");
dayItem.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
RadioMenuItem nightItem = new RadioMenuItem("夜晚模式");
nightItem.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
autoItem.setToggleGroup(themeToggleGroup);
dayItem.setToggleGroup(themeToggleGroup);
nightItem.setToggleGroup(themeToggleGroup);
autoItem.setSelected(true); // 默认自动切换
autoItem.setOnAction(e -> {
autoTheme = true;
applyTheme(primaryStage.getScene());
});
dayItem.setOnAction(e -> {
autoTheme = false;
applyDayTheme(primaryStage.getScene());
Image icon = new Image("C:///Users/lenovo/Desktop/绘制艺术插.png");
primaryStage.getIcons().add(icon);
});
nightItem.setOnAction(e -> {
autoTheme = false;
applyNightTheme(primaryStage.getScene());
Image icon = new Image("C:///Users/lenovo/Desktop/绘制艺术插画.png");
primaryStage.getIcons().add(icon);
});
themeMenu.getItems().addAll(autoItem, dayItem, nightItem);
menuBar.getMenus().addAll(operationMenu, themeMenu);
// 创建布局并添加控件
VBox vbox = new VBox(10);
vbox.getChildren().addAll(menuBar, listView, addButton, removeButton, changeButton);
// 设置场景并应用初始主题
Scene scene = new Scene(vbox, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
// 初始应用主题
applyTheme(scene);
LocalTime now = LocalTime.now();
if (now.isAfter(LocalTime.of(6, 0)) && now.isBefore(LocalTime.of(17, 30))) {
Image icon = new Image("C:///Users/lenovo/Desktop/绘制艺术插.png");
primaryStage.getIcons().add(icon);
} else {
Image icon = new Image("C:///Users/lenovo/Desktop/绘制艺术插画.png");
primaryStage.getIcons().add(icon);
}
}
/**
* 加载Minecraft字体
*/
private void loadMinecraftFont() {
try {
// 尝试从系统字体加载
Font.loadFont("file:/C:/Windows/Fonts/Minecraft.ttf", FONT_SIZE);
System.out.println("Minecraft字体加载成功");
} catch (Exception e) {
System.err.println("无法从系统加载Minecraft字体,使用默认字体");
e.printStackTrace();
}
}
/**
* 设置对话框字体
*/
private void setDialogFont(Dialog<?> dialog) {
// 设置对话框标题字体
dialog.setTitle("修改项");
// 设置对话框内容字体
dialog.getDialogPane().setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
// 设置按钮字体
ButtonBar buttonBar = (ButtonBar) dialog.getDialogPane().lookup(".button-bar");
if (buttonBar != null) {
buttonBar.getButtons().forEach(button -> {
button.setStyle(String.format("-fx-font-family: '%s'; -fx-font-size: %.1fpx;", FONT_NAME, FONT_SIZE));
});
}
}
/**
* 显示当前项目的总览信息。
*
* @param items ObservableList of String items to display in the overview.
*/
private void showOverview(ObservableList<String> items) {
StringBuilder sb = new StringBuilder("当前项目列表:\n");
for (String item : items) {
sb.append("- ").append(item).append("\n");
}
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("项目总览");
alert.setHeaderText(null);
alert.setContentText(sb.toString());
// 设置对话框字体
setDialogFont(alert);
alert.showAndWait();
}
/**
* 添加新项目到列表中。
*
* @param items ObservableList of String to which the new item will be added.
*/
private void addNewItem(ObservableList<String> items) {
TextInputDialog dialog = new TextInputDialog();
dialog.setTitle("添加项目");
dialog.setHeaderText("请输入要添加的项目名称");
dialog.setContentText("名称:");
// 设置对话框字体
setDialogFont(dialog);
Optional<String> result = dialog.showAndWait();
result.ifPresent(name -> {
if (!name.trim().isEmpty()) {
items.add(name);
}
});
}
/**
* 根据当前时间应用白天或夜晚模式的主题。
*
* @param scene The scene to which the theme will be applied.
*/
private void applyTheme(Scene scene) {
LocalTime now = LocalTime.now();
if (now.isAfter(LocalTime.of(6, 0)) && now.isBefore(LocalTime.of(17, 30))) {
applyDayTheme(scene);
} else {
applyNightTheme(scene);
}
}
/**
* 应用白天模式的主题。
*
* @param scene The scene to which the day theme will be applied.
*/
private void applyDayTheme(Scene scene) {
scene.getStylesheets().clear();
scene.getRoot().setStyle(STYLE_DAY_WITH_BG);
}
/**
* 应用夜晚模式的主题。
*
* @param scene The scene to which the night theme will be applied.
*/
private void applyNightTheme(Scene scene) {
scene.getStylesheets().clear();
scene.getRoot().setStyle(STYLE_NIGHT_WITH_EFFECT);
}
public static void main(String[] args) {
launch(args);
}
}
印象最深的题
7-4 NCHU_统计Java程序中关键词的出现次数
编写程序统计一个输入的Java源码中关键字(区分大小写)出现的次数。说明如下:
Java中共有53个关键字
从键盘输入一段源码,统计这段源码中出现的关键字的数量
- 注释中出现的关键字不用统计
- 字符串中出现的关键字不用统计
- 统计出的关键字及数量按照关键字升序进行排序输出
- 未输入源码则认为输入非法
输入格式:
输入Java源码字符串,可以一行或多行,以exit行作为结束标志
输出格式:
当未输入源码时,程序输出Wrong Format
当没有统计数据时,输出为空
当有统计数据时,关键字按照升序排列,每行输出一个关键字及数量,格式为数量\t关键字
输入样例:
在这里给出一组输入。例如:
//Test public method
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);
}
exit
输出样例:
在这里给出相应的输出。例如:
1 float
3 if
2 int
2 new
2 public
3 this
2 throw
1. 关键字集合的初始化
首先创建了一个包含所有 Java 关键字的集合k,使用HashSet存储这些关键字,这样可以快速判断一个词是否是关键字。
2. 源码的读取与处理
使用Scanner读取输入,直到遇到 "exit" 行结束
将读取的所有行拼接成一个完整的字符串
如果没有读取到任何源码行,输出 "Wrong Format" 并退出程序
3. 源码的预处理
编写了p方法来处理源码字符串,主要目的是去除注释和字符串内容:
使用状态机处理不同的情况:普通文本、双引号字符串、单引号字符、单行注释和多行注释
在不同的状态下,将非代码部分替换为空格,保留代码部分
4. 关键字的统计
编写了ck方法来统计关键字出现的次数:
首先对预处理后的字符串进行进一步清理,替换各种符号为空格
使用正则表达式将非字母字符替换为空格
将处理后的字符串按空格分割成单词数组
遍历单词数组,统计在关键字集合中出现的单词次数
5. 结果的排序与输出
使用TreeMap对统计结果进行排序,因为TreeMap会自动按照键的自然顺序排序
遍历排序后的结果,按要求格式输出
为什么上面的方法名和变量名那么简单?
emmm......
不要在意这些细节问题,来康康代码:
点击查看源码
import java.util.*;
import java.io.*;
public class Main {
private static final Set<String> k = new HashSet<>(Arrays.asList(
"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) throws IOException {
Scanner s = new Scanner(System.in);
StringBuilder c = new StringBuilder();
boolean h = false;
while (s.hasNextLine()) {
String l = s.nextLine();
if (l.trim().equalsIgnoreCase("exit")) {
break;
}
c.append(l).append("\n");
h = true;
}
if (!h) {
System.out.println("Wrong Format");
return;
}
String pc = p(c.toString());
Map<String, Integer> kc = ck(pc);
if (!kc.isEmpty()) {
TreeMap<String, Integer> sk = new TreeMap<>(kc);
for (Map.Entry<String, Integer> e : sk.entrySet()) {
System.out.printf("%d\t%s\n", e.getValue(), e.getKey());
}
}
}
private static String p(String code) {
StringBuilder r = new StringBuilder();
int st = 0;
for (int i = 0; i < code.length(); i++) {
char ch = code.charAt(i);
switch (st) {
case 0:
if (ch == '"') {
st = 1;
r.append(' ');
} else if (ch == '\'') {
st = 2;
r.append(' ');
} else if (ch == '/' && i + 1 < code.length()) {
char next = code.charAt(i + 1);
if (next == '/') {
st = 3;
r.append(' ');
i++;
} else if (next == '*') {
st = 4;
r.append(' ');
i++;
} else {
r.append(ch);
}
} else {
r.append(ch);
}
break;
case 1:
if (ch == '"' && (i == 0 || code.charAt(i - 1) != '\\')) {
st = 0;
}
r.append(' ');
break;
case 2:
if (ch == '\'' && (i == 0 || code.charAt(i - 1) != '\\')) {
st = 0;
}
r.append(' ');
break;
case 3:
if (ch == '\n') {
st = 0;
r.append(ch);
} else {
r.append(' ');
}
break;
case 4:
if (ch == '*' && i + 1 < code.length() && code.charAt(i + 1) == '/') {
st = 0;
r.append(' ');
i++;
} else {
r.append(' ');
}
break;
}
}
return r.toString();
}
private static Map<String, Integer> ck(String code) {
code = code.replace("[", " ");
code = code.replace("]", " ");
code = code.replace("-", "a");
code = code.replace("*", "a");
code = code.replace("/", "a");
code = code.replace("+", "a");
code = code.replace(">", "a");
code = code.replace("=", "a");
code = code.replace("!", "a");
code = code.replace(":", "a");
code = code.replace("\\", "a");
code = code.replaceAll("[^a-zA-Z]", " ");
Map<String, Integer> cnt = new HashMap<>();
String[] w = code.split("\\s+");
for (String word : w) {
if (!word.isEmpty() && k.contains(word)) {
cnt.put(word, cnt.getOrDefault(word, 0) + 1);
}
}
return cnt;
}
}
采坑心得
在整门课程的学习过程中,不可避免地走了许多弯路,也从中吸取了宝贵的经验教训。
在 PTA 作业中,初期由于对题目要求理解不透彻,经常出现代码逻辑错误。例如,在一道关于字符串处理的题目中,没有正确理解题目中对字符串格式和操作的要求,导致编写的代码虽然能够运行,但无法通过测试用例。后来意识到,在做题前一定要仔细阅读题目描述,分析输入输出的要求和边界条件,必要时可以通过手动计算或绘制流程图来梳理思路。同时,养成良好的代码注释习惯,方便自己和他人理解代码逻辑,也有助于在调试过程中快速定位问题。
在实验过程中,调试代码是一个充满挑战的环节。当程序出现错误时,往往不知道从何处入手排查问题。曾经在一个复杂的系统功能实现中,程序运行时出现了空指针异常,但由于代码结构复杂,很难确定具体的出错位置。经过多次尝试,学会了使用调试工具,通过设置断点、逐步执行代码等方式,观察变量的值和程序的执行流程,从而找到问题所在。此外,遇到问题时,不能盲目地修改代码,要先分析问题产生的原因,查阅相关资料或向同学、老师请教,避免引入新的错误。
在学习面向对象技术时,对于一些概念的混淆也导致了不少问题。例如,在使用继承和接口时,有时会错误地选择使用方式,导致代码结构不合理。通过查阅资料和与同学讨论,深入理解了继承和接口的区别和适用场景,明白了在设计类结构时,要根据具体的需求和业务逻辑来选择合适的技术。同时,在学习新知识时,要及时进行总结和归纳,通过对比分析加深对概念的理解,避免混淆。
改进建议及总结
课程综合性总结
通过本学期的 Java 课程学习,在面向对象编程、Java 核心技术以及实际项目开发等方面都有了显著的提升。课程的教学环节设计合理,从理论学习到实践操作,逐步引导我们掌握 Java 编程技能。通过 Blog 作业、PTA 作业和实验等多种形式的练习,不仅加深了对知识的理解,还提高了编程实践能力和问题解决能力。同时,线上线下课程的结合,为我们提供了丰富的学习资源和良好的学习环境。但在学习过程中也发现了一些不足之处,需要在今后的学习和教学中加以改进。
改进建议
-
教学内容方面:在讲解一些复杂的概念和技术时,如设计模式、多线程编程等,可以增加更多的实际案例和场景分析,帮助我们更好地理解其应用价值和使用方法。对于一些容易混淆的概念,如抽象类和接口、继承和组合等,可以进行更深入的对比讲解,并通过实际的代码示例进行演示,加深我们的理解。
-
作业和实验方面:在 PTA 作业和实验题目设置上,可以增加一些具有创新性和开放性的题目,鼓励我们发挥自己的想象力和创造力,运用所学知识解决实际问题。同时,对于作业和实验的反馈可以更加及时和详细,除了指出错误之外,还可以提供一些优化建议和思路拓展,帮助我们提高代码质量和编程水平。
-
课上及课下组织方式方面:在课堂教学中,可以增加更多的互动环节,如小组讨论、案例分析、编程演示等,提高我们的参与度和学习积极性。此外,可以建立一个在线学习社区或论坛,方便我们在课后进行问题交流和知识分享,教师也可以在上面及时解答我们的疑问,提供学习指导。
总结
这门 Java 课程虽然充满挑战,但也让我收获颇丰。通过对各个教学环节的参与和学习,不仅掌握了 Java 编程的核心技术,还培养了自己的编程思维和解决问题的能力。在学习过程中遇到的困难和挫折,都成为了我成长的垫脚石。希望在今后的学习和工作中,能够继续运用所学知识,不断提升自己的技术水平。同时,也希望课程能够不断改进和完善,为更多的同学提供优质的学习资源和良好的学习体验,帮助大家在 Java 编程的道路上取得更好的成绩。
以上就是我对本门课程的总结性 Blog,通过对课程的全面回顾和反思,希望能够为今后的学习和教学提供有益的参考。
posted on 2025-06-16 10:24 content2024 阅读(52) 评论(0) 收藏 举报