Compare commits

...

No commits in common. 'main' and 'master' have entirely different histories.
main ... master

  1. 30
      .gitignore
  2. 10
      .idea/.gitignore
  3. 6
      .idea/misc.xml
  4. 8
      .idea/modules.xml
  5. 6
      .idea/vcs.xml
  6. 9
      2-W5/w5基础版/Circle.java
  7. 9
      2-W5/w5基础版/Rectangle.java
  8. 9
      2-W5/w5基础版/Shape.java
  9. 24
      2-W5/w5基础版/TestShape.java
  10. BIN
      2-W5/w5基础版/基础版运行结果.png
  11. 20
      2-W5/w5挑战版/Person.java
  12. 42
      2-W5/w5挑战版/PersonManager.java
  13. 22
      2-W5/w5挑战版/Student.java
  14. 22
      2-W5/w5挑战版/Teacher.java
  15. 20
      2-W5/w5挑战版/TestPersonSystem.java
  16. BIN
      2-W5/w5挑战版/挑战版运行结果.png
  17. 8
      2-W5/w5挑战版/添加属性问题回答
  18. 18
      2-W5/w5进阶版/Computer.java
  19. 14
      2-W5/w5进阶版/Keyboard.java
  20. 14
      2-W5/w5进阶版/Mouse.java
  21. 17
      2-W5/w5进阶版/TestUSB.java
  22. 7
      2-W5/w5进阶版/USB.java
  23. BIN
      2-W5/w5进阶版/进阶版运行结果.png
  24. 5
      DataCleaner.iml
  25. BIN
      out/production/IdeaProjects/Circle.class
  26. BIN
      out/production/IdeaProjects/Main.class
  27. BIN
      out/production/IdeaProjects/Rectangle.class
  28. BIN
      out/production/IdeaProjects/Shape.class
  29. BIN
      out/production/IdeaProjects/ShapeUtil.class
  30. BIN
      out/production/IdeaProjects/Triangle.class
  31. 9
      w1/README.md
  32. 116
      w1/TemperatureConverter.java
  33. BIN
      w1/d0a5deb6978adf47e24fcb058d237736.jpg
  34. 38
      w2/DataCleaner.java
  35. 112
      w3/Car.java
  36. 39
      w3/TestCar.java
  37. 23
      w3/实验报告
  38. BIN
      w3/类图.png
  39. BIN
      w3/运行结果.png
  40. 15
      w5/Circle.java
  41. 18
      w5/Main.java
  42. 17
      w5/Rectangle.java
  43. 4
      w5/Shape.java
  44. 11
      w5/ShapeUtil.java
  45. 17
      w5/Triangle.java
  46. 21
      w5/实验报告
  47. 5
      w6/Animal.java
  48. 9
      w6/Cat.java
  49. 15
      w6/Dog.java
  50. 5
      w6/Swimmable.java
  51. 31
      w6/TestAnimal.java
  52. BIN
      w6/运行结果.png

30
.gitignore

@ -0,0 +1,30 @@
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
!**/src/test/**/out/
.kotlin
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

10
.idea/.gitignore

@ -0,0 +1,10 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 已忽略包含查询文件的默认文件夹
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

6
.idea/misc.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/DataCleaner.iml" filepath="$PROJECT_DIR$/DataCleaner.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

9
2-W5/w5基础版/Circle.java

@ -1,9 +0,0 @@
package w5基础版;
// 圆
public class Circle extends Shape {
@Override
public void draw() {
System.out.println("🔵 绘制圆形");
}
}

9
2-W5/w5基础版/Rectangle.java

@ -1,9 +0,0 @@
package w5基础版;
// 矩形
public class Rectangle extends Shape {
@Override
public void draw() {
System.out.println("🔲 绘制矩形");
}
}

9
2-W5/w5基础版/Shape.java

@ -1,9 +0,0 @@
package w5基础版;
// 父类
public class Shape {
// draw方法
public void draw() {
System.out.println("绘制图形");
}
}

24
2-W5/w5基础版/TestShape.java

@ -1,24 +0,0 @@
package w5基础版;
// 测试类
public class TestShape {
public static void main(String[] args) {
// 1. 创建对象
Shape circle = new Circle();
Shape rectangle = new Rectangle();
// 2. 调用统一绘制方法
drawShape(circle);
drawShape(rectangle);
// 3. 直接调用
System.out.println("\n=== 直接调用 ===");
circle.draw();
rectangle.draw();
}
// 核心方法:接收父类引用,实现多态调用
public static void drawShape(Shape s) {
s.draw();
}
}

BIN
2-W5/w5基础版/基础版运行结果.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

20
2-W5/w5挑战版/Person.java

@ -1,20 +0,0 @@
package w5挑战版;
// 人类(父类)
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter
public String getName() { return name; }
public int getAge() { return age; }
// 通用方法
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}

42
2-W5/w5挑战版/PersonManager.java

@ -1,42 +0,0 @@
package w5挑战版;
import java.util.List;
import java.util.ArrayList;
// 人员管理器(重构关键)
public class PersonManager {
// 用List存储Person,容纳所有子类对象
private List<Person> personList = new ArrayList<>();
// 核心重构:合并成一个方法,接收父类引用
public void addPerson(Person person) {
personList.add(person);
System.out.println("添加成功:" + person.getClass().getSimpleName());
}
// 显示所有人信息(多态调用)
public void showAllPersons() {
System.out.println("\n=== 所有人员列表 ===");
for (Person p : personList) {
p.showInfo();
}
}
// 解决特定属性问题:使用instanceof判断类型并获取属性
public void checkPersonDetails() {
System.out.println("\n=== 人员详情检查 ===");
for (Person p : personList) {
if (p instanceof Student) {
Student s = (Student) p;
// 现在Student有了getStudentId(),就不会报错了
System.out.println(s.getName() + " 是学生,学号:" + s.getStudentId());
} else if (p instanceof Teacher) {
Teacher t = (Teacher) p;
// 现在Teacher有了getTeacherId(),就不会报错了
System.out.println(t.getName() + " 是老师,工号:" + t.getTeacherId());
} else {
System.out.println(p.getName() + " 是普通人员");
}
}
}
}

22
2-W5/w5挑战版/Student.java

@ -1,22 +0,0 @@
package w5挑战版;
// 学生
public class Student extends Person {
private String studentId; // 学号
public Student(String name, int age, String studentId) {
super(name, age);
this.studentId = studentId;
}
// 重写显示信息
@Override
public void showInfo() {
System.out.printf("【学生】%s | 年龄:%d | 学号:%s%n", getName(), getAge(), studentId);
}
// 🔥 必须加这个getter!否则PersonManager里调用不到
public String getStudentId() {
return studentId;
}
}

22
2-W5/w5挑战版/Teacher.java

@ -1,22 +0,0 @@
package w5挑战版;
// 老师
public class Teacher extends Person {
private String teacherId; // 工号
public Teacher(String name, int age, String teacherId) {
super(name, age);
this.teacherId = teacherId;
}
// 重写显示信息
@Override
public void showInfo() {
System.out.printf("【老师】%s | 年龄:%d | 工号:%s%n", getName(), getAge(), teacherId);
}
// 🔥 必须加这个getter!否则PersonManager里调用不到
public String getTeacherId() {
return teacherId;
}
}

20
2-W5/w5挑战版/TestPersonSystem.java

@ -1,20 +0,0 @@
package w5挑战版;
// 测试重构后的系统
public class TestPersonSystem {
public static void main(String[] args) {
PersonManager manager = new PersonManager();
// 统一添加(无需区分学生/老师,全部是Person)
manager.addPerson(new Student("张三", 18, "2025001"));
manager.addPerson(new Teacher("李老师", 40, "T001"));
manager.addPerson(new Student("李四", 19, "2025002"));
// 显示所有人
manager.showAllPersons();
// 检查特定属性
manager.checkPersonDetails();
}
}

BIN
2-W5/w5挑战版/挑战版运行结果.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

8
2-W5/w5挑战版/添加属性问题回答

@ -1,8 +0,0 @@
核心思路:利用多态,将 addStudent 和 addTeacher 合并为 addPerson(Person p),用父类引用统一接收所有子类对象,存入 List<Person> 统一管理,实现代码复用和统一入口。
2. 特有属性的处理方案:
◦ 方案一(作业首选):instanceof 类型判断 + 向下转型。在需要访问子类特有属性时,通过 instanceof 判断对象的真实类型,将父类引用向下转型为对应的子类类型,再调用子类特有的 getter 方法(如 getStudentId()/getTeacherId()),从而获取特有属性。
◦ 方案二(进阶):模板方法模式。在父类 Person 中定义抽象方法 getSpecialInfo(),让 Student和 Teacher 各自实现该方法,返回自己的特有属性,父类统一调用该方法,无需类型判断,代码更简洁,符合开闭原则。
3. 优势:
◦ 合并方法后,减少了代码冗余,统一了人员添加的入口,提升了代码的可维护性。
◦ 多态保证了新增人员类型(如「管理员」)时,无需修改 addPerson 方法,仅需新增子类即可,符合面向对象的设计思想。
4. 注意事项:向下转型时,必须先通过 instanceof 判断类型,避免 ClassCastException 类型转换异常;子类特有属性必须通过 getter 方法访问,保证封装性。

18
2-W5/w5进阶版/Computer.java

@ -1,18 +0,0 @@
package w5进阶版;
// 电脑
public class Computer {
// 使用USB设备的方法(多态参数)
public void useUSB(USB usb) {
System.out.println("\n电脑开始使用USB设备...");
usb.open();
// 模拟工作
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
usb.close();
System.out.println("USB设备使用完毕\n");
}
}

14
2-W5/w5进阶版/Keyboard.java

@ -1,14 +0,0 @@
package w5进阶版;
// 键盘
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("⌨️ 键盘已连接并打开");
}
@Override
public void close() {
System.out.println("⌨️ 键盘已关闭并断开");
}
}

14
2-W5/w5进阶版/Mouse.java

@ -1,14 +0,0 @@
package w5进阶版;
// 鼠标
public class Mouse implements USB {
@Override
public void open() {
System.out.println("🖱️ 鼠标已连接并打开");
}
@Override
public void close() {
System.out.println("🖱️ 鼠标已关闭并断开");
}
}

17
2-W5/w5进阶版/TestUSB.java

@ -1,17 +0,0 @@
package w5进阶版;
// 测试
public class TestUSB {
public static void main(String[] args) {
// 创建电脑对象
Computer myComputer = new Computer();
// 创建USB设备
USB mouse = new Mouse();
USB keyboard = new Keyboard();
// 插入不同设备
myComputer.useUSB(mouse);
myComputer.useUSB(keyboard);
}
}

7
2-W5/w5进阶版/USB.java

@ -1,7 +0,0 @@
package w5进阶版;
// USB接口
public interface USB {
void open(); // 打开设备
void close(); // 关闭设备
}

BIN
2-W5/w5进阶版/进阶版运行结果.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

5
w1/IdeaProjects.iml → DataCleaner.iml

@ -2,9 +2,8 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/..">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/../w5" isTestSource="false" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

BIN
out/production/IdeaProjects/Circle.class

Binary file not shown.

BIN
out/production/IdeaProjects/Main.class

Binary file not shown.

BIN
out/production/IdeaProjects/Rectangle.class

Binary file not shown.

BIN
out/production/IdeaProjects/Shape.class

Binary file not shown.

BIN
out/production/IdeaProjects/ShapeUtil.class

Binary file not shown.

BIN
out/production/IdeaProjects/Triangle.class

Binary file not shown.

9
w1/README.md

@ -1,9 +0,0 @@
# java
# 温度转换器 (Java 版)
将 Python 温度转换程序移植为 Java,支持摄氏度与华氏度互转。
实现了三种运行模式:交互式、命令行参数、批量文件处理。
## 编译
```bash
javac TemperatureConverter.java

116
w1/TemperatureConverter.java

@ -1,116 +0,0 @@
import java.io.*;
import java.util.*;
public class TemperatureConverter {
/**
* 将摄氏度转换为华氏度
*
* @param c 摄氏温度
* @return 对应的华氏温度
*/
public static double celsiusToFahrenheit(double c) {
return c * 9.0 / 5.0 + 32.0;
}
/**
* 将华氏度转换为摄氏度
*
* @param f 华氏温度
* @return 对应的摄氏温度
*/
public static double fahrenheitToCelsius(double f) {
return (f - 32.0) * 5.0 / 9.0;
}
/**
* 交互式模式从标准输入读取一行解析并转换
*/
private static void interactiveMode() {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入要转换的温度与单位(例如 36.6 C 或 97 F):");
String line = scanner.nextLine().trim();
if (line.isEmpty()) {
System.out.println("输入为空,程序退出。");
return;
}
processInputLine(line);
}
/**
* 处理单行输入字符串格式如 "36.6 C" "97 F"
* 若解析成功则输出转换结果否则打印错误信息
*/
private static void processInputLine(String line) {
String[] parts = line.split("\\s+");
if (parts.length == 0) return;
try {
double value = Double.parseDouble(parts[0]);
String unit = (parts.length > 1) ? parts[1].toUpperCase() : "C";
convertAndPrint(value, unit);
} catch (NumberFormatException e) {
System.out.println("输入解析失败,请按示例输入数值与单位,例如:36.6 C");
}
}
/**
* 根据数值和单位进行转换并打印结果
*/
private static void convertAndPrint(double value, String unit) {
if (unit.startsWith("C")) {
double f = celsiusToFahrenheit(value);
System.out.printf("%.2f °C = %.2f °F%n", value, f);
} else if (unit.startsWith("F")) {
double c = fahrenheitToCelsius(value);
System.out.printf("%.2f °F = %.2f °C%n", value, c);
} else {
System.out.println("未知单位,请使用 C 或 F。");
}
}
/**
* 命令行参数模式两个参数分别为数值和单位
*/
private static void commandLineMode(String valueStr, String unitStr) {
try {
double value = Double.parseDouble(valueStr);
String unit = unitStr.toUpperCase();
convertAndPrint(value, unit);
} catch (NumberFormatException e) {
System.out.println("无效的数值参数,请提供正确的数字。");
}
}
/**
* 批量文件模式从指定文件逐行读取每行格式同交互输入
*/
private static void batchFileMode(String fileName) {
try (Scanner fileScanner = new Scanner(new File(fileName))) {
while (fileScanner.hasNextLine()) {
String line = fileScanner.nextLine().trim();
if (line.isEmpty()) continue;
processInputLine(line);
}
} catch (FileNotFoundException e) {
System.out.println("文件未找到: " + fileName);
}
}
public static void main(String[] args) {
if (args.length == 0) {
// 无参数:交互模式
interactiveMode();
} else if (args.length == 2) {
// 两个参数:命令行模式
commandLineMode(args[0], args[1]);
} else if (args.length == 1) {
// 一个参数:视为文件名,进行批量转换
batchFileMode(args[0]);
} else {
System.out.println("用法:");
System.out.println(" 交互模式: java TemperatureConverter");
System.out.println(" 单次转换: java TemperatureConverter <数值> <单位(C/F)>");
System.out.println(" 批量转换: java TemperatureConverter <文件名>");
}
}
}

BIN
w1/d0a5deb6978adf47e24fcb058d237736.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

38
w2/DataCleaner.java

@ -1,38 +0,0 @@
public class DataCleaner {
public static void main(String[] args) {
// 给定的传感器原始数据数组
int[] sensorData = {85, -5, 92, 0, 105, 999, 88, 76};
int validSum = 0; // 有效数据总和
int validCount = 0; // 有效数据个数
// 1. 遍历数组的每一个元素
for (int num : sensorData) {
// 3. 致命错误:遇到999,直接终止整个流程
if (num == 999) {
System.out.println("致命错误:传感器掉线,终止处理");
break; // 直接跳出整个for循环,不再处理后面的数据
}
// 2. 无效数据:0/负数/大于100(且不是999,已经被上面过滤了)
if (num < 1 || num > 100) {
System.out.println("警告:发现越界数据[" + num + "],已跳过");
continue; // 跳过当前这次循环,不执行后面的累加逻辑
}
// 1. 正常数据:1~100之间,计入有效数据
validSum += num;
validCount++;
}
// 4. 最终输出:计算平均值(处理整数除法陷阱)
if (validCount > 0) {
// 关键:把int转成double,避免整数除法(比如10/3=3,而不是3.333)
double avg = (double) validSum / validCount;
// 保留2位小数输出,更美观
System.out.printf("有效数据的平均值为:%.2f\n", avg);
} else {
System.out.println("无有效数据");
}
}
}

112
w3/Car.java

@ -1,112 +0,0 @@
public class Car {
// 1. 私有属性(全部private,完全符合要求)
private final String licensePlate; // 车牌号(不可变,用final修饰)
private String brand; // 品牌
private String model; // 型号
private double dailyRent; // 日租金(元/天)
private boolean isRented; // 是否已出租(true=已租,false=未租)
// 5. 静态成员:统计车辆总数(选做加分项,直接实现)
private static int totalCars = 0;
// 2. 构造方法:全参构造(isRented初始化为false,totalCars自增)
public Car(String licensePlate, String brand, String model, double dailyRent) {
this.licensePlate = licensePlate;
this.brand = brand;
this.model = model;
// 日租金校验:如果传入非法值,用默认300
if (dailyRent > 0) {
this.dailyRent = dailyRent;
} else {
this.dailyRent = 300.0;
System.out.println("警告:日租金必须大于0,已自动设置为默认值300元/天");
}
this.isRented = false; // 初始未出租
totalCars++; // 每创建一个对象,总数+1
}
// 2. 构造方法重载:三参构造(用this()调用全参构造,默认日租金300)
public Car(String licensePlate, String brand, String model) {
this(licensePlate, brand, model, 300.0); // 调用全参构造
}
// 3. Getter/Setter(严格符合要求)
// 车牌号:只提供getter,无setter(不可修改)
public String getLicensePlate() {
return licensePlate;
}
// 品牌:getter+setter
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
// 型号:getter+setter
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
// 日租金:getter+setter,setter必须校验>0
public double getDailyRent() {
return dailyRent;
}
public void setDailyRent(double dailyRent) {
if (dailyRent > 0) {
this.dailyRent = dailyRent;
} else {
System.out.println("错误:日租金必须大于0,修改失败,保持原值:" + this.dailyRent);
}
}
// 出租状态:只提供getter(isRented()),无setter(只能通过业务方法修改)
public boolean isRented() {
return isRented;
}
// 5. 静态方法:获取车辆总数
public static int getTotalCars() {
return totalCars;
}
// 4. 业务方法:租车
public void rentCar() {
if (isRented) {
System.out.println("车辆已租出,无法再次租用");
} else {
isRented = true;
System.out.println("车辆已成功租出");
}
}
// 4. 业务方法:还车
public void returnCar() {
if (!isRented) {
System.out.println("车辆未被租用,无需归还");
} else {
isRented = false;
System.out.println("车辆已成功归还");
}
}
// 4. 业务方法:计算租金(仅计算,不修改属性)
public double calculateRent(int days) {
if (days <= 0) {
System.out.println("警告:租用天数必须大于0,返回0");
return 0;
}
return dailyRent * days;
}
// 辅助方法:打印车辆信息(测试用,方便输出)
public void displayInfo() {
System.out.printf("车牌号:%s | 品牌:%s | 型号:%s | 日租金:%.2f元/天 | 状态:%s%n",
licensePlate, brand, model, dailyRent, isRented ? "已出租" : "未出租");
}
}

39
w3/TestCar.java

@ -1,39 +0,0 @@
public class TestCar {
public static void main(String[] args) {
System.out.println("=== 1. 创建车辆对象(两种构造方法) ===");
// 用全参构造创建车辆1
Car car1 = new Car("湘A12345", "特斯拉", "Model 3", 500.0);
// 用三参构造创建车辆2(默认日租金300)
Car car2 = new Car("湘A67890", "比亚迪", "汉");
// 用全参构造创建车辆3(传入非法日租金-100,测试校验)
Car car3 = new Car("湘A00001", "五菱", "宏光MINI", -100.0);
System.out.println("\n=== 2. 打印所有车辆初始信息 ===");
car1.displayInfo();
car2.displayInfo();
car3.displayInfo();
System.out.println("\n=== 3. 测试租车/还车业务(car1) ===");
car1.rentCar(); // 第一次租车:成功
car1.rentCar(); // 第二次租车:提示已租出
car1.displayInfo(); // 查看状态
car1.returnCar(); // 第一次还车:成功
car1.returnCar(); // 第二次还车:提示未租出
car1.displayInfo(); // 查看状态
System.out.println("\n=== 4. 测试租金计算(car2租用5天) ===");
double rent = car2.calculateRent(5);
System.out.printf("车辆%s租用5天的总租金为:%.2f元%n", car2.getLicensePlate(), rent);
System.out.println("\n=== 5. 测试日租金setter非法修改(car3) ===");
System.out.println("修改前日租金:" + car3.getDailyRent());
car3.setDailyRent(-200); // 非法值:提示错误,保持原值
car3.setDailyRent(200); // 合法值:修改成功
System.out.println("修改后日租金:" + car3.getDailyRent());
System.out.println("\n=== 6. 静态成员:车辆总数 ===");
System.out.println("当前创建的车辆总数:" + Car.getTotalCars());
}
}

23
w3/实验报告

@ -1,23 +0,0 @@
一、核心代码
【文件夹内】
二、UML 类图
【文件夹内】
五、运行结果截图
【文件夹内】
六、AI 使用情况记录
1. 借助 AI 学习封装、构造方法重载、this 关键字的核心概念
2. 在 AI 指导下完成 Car 类的属性、构造方法、getter/setter、业务方法的编写
3. AI 帮助修正了数据校验逻辑、静态成员的实现,优化了代码规范性
4. AI 指导了 IDEA 类图的生成方法,快速完成可视化建模
5. AI 辅助撰写了实验报告,梳理了实验总结与问题分析
七、关键问题回答
问题:为什么 isRented 不提供 setter?如果直接提供 setRented (boolean) 会带来什么风险?
• 原因:isRented 是车辆的业务状态,必须通过 rentCar() 和 returnCar() 两个业务方法来修改,保证状态切换的逻辑合法性(比如不能重复租车、不能重复还车)。
• 风险:如果直接提供 setRented(),外部可以随意修改车辆状态,会导致业务逻辑混乱(比如车辆已租出却被强行设为未租出,造成租车公司管理混乱、数据错误),破坏了对象状态的封装性和合法性。
八、实验总结
1. 封装的好处:通过私有属性 + 公有方法,保护了对象内部状态,外部只能通过合法的方法修改数据,保证了数据的安全性和一致性。
2. 遇到的问题:
◦ 构造方法重载时 this() 的调用位置错误(必须放在第一行),AI 指导修正了位置
◦ 日租金 setter 忘记加数据校验,导致非法值可以修改,补充了 if (dailyRent > 0) 的判断
◦ isRented 不小心写了 setter,按照要求删除,只保留业务方法修改
3. 解决方法:通过 AI 逐行检查代码,对照实验要求修正,确保每一项都符合评分标准。

BIN
w3/类图.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

BIN
w3/运行结果.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

15
w5/Circle.java

@ -1,15 +0,0 @@
public class Circle extends Shape {
// 私有属性:半径
private double radius;
// 构造方法:创建圆时必须传入半径
public Circle(double radius) {
this.radius = radius;
}
// 重写父类抽象方法,实现圆的面积计算
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}

18
w5/Main.java

@ -1,18 +0,0 @@
public class Main {
public static void main(String[] args) {
// 1. 创建不同图形对象(多态:父类引用指向子类对象)
Shape circle = new Circle(2);
Shape rectangle = new Rectangle(3, 4);
Shape triangle = new Triangle(5, 4);
// 2. 统一打印面积
System.out.println("=== 圆的面积 ===");
ShapeUtil.printArea(circle);
System.out.println("=== 矩形的面积 ===");
ShapeUtil.printArea(rectangle);
System.out.println("=== 三角形的面积 ===");
ShapeUtil.printArea(triangle);
}
}

17
w5/Rectangle.java

@ -1,17 +0,0 @@
public class Rectangle extends Shape {
// 私有属性:长、宽
private double length;
private double width;
// 构造方法
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
// 重写父类方法
@Override
public double getArea() {
return length * width;
}
}

4
w5/Shape.java

@ -1,4 +0,0 @@
public abstract class Shape {
// 抽象方法:所有图形必须实现面积计算
public abstract double getArea();
}

11
w5/ShapeUtil.java

@ -1,11 +0,0 @@
public class ShapeUtil {
// 统一打印面积的静态方法:支持所有Shape子类
public static void printArea(Shape shape) {
if (shape == null) {
System.out.println("图形不能为空!");
return;
}
double area = shape.getArea();
System.out.printf("图形面积为:%.2f%n", area);
}
}

17
w5/Triangle.java

@ -1,17 +0,0 @@
public class Triangle extends Shape {
// 私有属性:底、高
private double base;
private double height;
// 构造方法
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
// 重写父类方法
@Override
public double getArea() {
return base * height / 2;
}
}

21
w5/实验报告

@ -1,21 +0,0 @@
图形面积计算器重构实验报告
一、AI 使用情况记录
1. 概念学习:通过 AI 学习抽象类、继承、多态的核心概念,理解 “统一处理不同类型对象” 的设计思想,明确本次实验的核心目标。
2. 代码框架生成:借助 AI 生成抽象类 Shape、图形子类、ShapeUtil 工具类的基础代码框架,明确各类型的职责与结构。
3. 代码修正与优化:在 AI 指导下修正构造方法参数、@Override注解使用等细节,优化代码可读性与规范性。
4. IDE 操作指导:通过 AI 学习 IntelliJ IDEA 中创建项目、编写代码、运行程序及生成 UML 类图的完整操作流程,解决了类图生成、导出等问题。
5. 报告撰写辅助:利用 AI 梳理实验报告结构,获取 “组合 vs 继承” 问题的解答思路,确保报告内容完整、逻辑清晰。
二、组合vs继承问题回答
五、组合 vs 继承问题回答
1. 核心概念
• 继承(is-a):表示 “子类是一种父类” 的分类关系,通过 extends 关键字实现,子类可以复用父类的属性与方法,并通过重写实现多态。继承会导致类之间强耦合,父类的修改会影响所有子类。
• 组合(has-a):表示 “一个类包含另一个类的对象” 的包含关系,通过成员变量实现,将复杂功能拆分为多个独立类,降低耦合度,提高代码灵活性与可维护性。
2. 本实验中的选择与原因
本实验采用继承方案,原因如下:
• Circle、Rectangle、Triangle 都是 Shape 的一种(满足 is-a 关系),符合继承的适用场景。
• 通过继承抽象类 Shape,可以利用多态特性,让 ShapeUtil统一处理所有图形对象,无需为每个图形编写单独的打印方法,实现了代码复用与统一管理。
• 若采用组合方案,无法自然体现 “图形分类” 的层次关系,也难以实现统一调用的多态效果。
3. 适用场景总结
• 优先使用组合:当类之间是 “包含 / 使用” 关系(has-a),需要灵活复用功能、降低耦合时,优先选择组合。
• 使用继承:当类之间是 “分类 / 从属” 关系(is-a),需要复用父类逻辑并实现多态时,才使用继承。
• 设计原则:优先使用组合,而非继承,避免继承带来的强耦合问题,只有在明确满足 is-a 关系且需要多态特性时,才考虑使用继承。

5
w6/Animal.java

@ -1,5 +0,0 @@
// 抽象类:Animal
public abstract class Animal {
// 抽象方法:发出声音,子类必须重写
public abstract void makeSound();
}

9
w6/Cat.java

@ -1,9 +0,0 @@
// Cat类:仅继承Animal,不实现Swimmable
public class Cat extends Animal {
// 重写父类抽象方法:发出叫声
@Override
public void makeSound() {
System.out.println("喵喵喵!");
}
}

15
w6/Dog.java

@ -1,15 +0,0 @@
// Dog类:继承Animal,实现Swimmable接口
public class Dog extends Animal implements Swimmable {
// 重写父类抽象方法:发出叫声
@Override
public void makeSound() {
System.out.println("汪汪汪!");
}
// 实现接口的swim方法
@Override
public void swim() {
System.out.println("小狗在水里游泳~");
}
}

5
w6/Swimmable.java

@ -1,5 +0,0 @@
// 接口:Swimmable(可游泳的能力)
public interface Swimmable {
// 抽象方法:游泳
void swim();
}

31
w6/TestAnimal.java

@ -1,31 +0,0 @@
// 测试类:main方法,测试多态调用
public class TestAnimal {
public static void main(String[] args) {
System.out.println("=== 1. 多态调用Animal父类引用 ===");
// 父类引用指向子类对象(多态核心)
Animal dog = new Dog();
Animal cat = new Cat();
// 多态调用makeSound():运行时自动执行子类的方法
dog.makeSound(); // 输出:汪汪汪!
cat.makeSound(); // 输出:喵喵喵!
System.out.println("\n=== 2. 测试Dog的游泳能力(接口多态) ===");
// 接口引用指向实现类对象(接口多态)
Swimmable swimmableDog = new Dog();
swimmableDog.swim(); // 输出:小狗在水里游泳~
System.out.println("\n=== 3. 类型判断与向下转型(可选拓展) ===");
// 判断Animal对象是否能游泳(instanceof)
if (dog instanceof Swimmable) {
System.out.println("Dog是可游泳的");
// 向下转型为Swimmable,调用swim方法
((Swimmable) dog).swim();
}
if (cat instanceof Swimmable) {
System.out.println("Cat是可游泳的");
} else {
System.out.println("Cat不会游泳");
}
}
}

BIN
w6/运行结果.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 KiB

Loading…
Cancel
Save