diff --git a/w3/Car.java b/w3/Car.java new file mode 100644 index 0000000..cc78399 --- /dev/null +++ b/w3/Car.java @@ -0,0 +1,112 @@ + +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 ? "已出租" : "未出租"); + } +} \ No newline at end of file diff --git a/w3/TestCar.java b/w3/TestCar.java new file mode 100644 index 0000000..20bd795 --- /dev/null +++ b/w3/TestCar.java @@ -0,0 +1,39 @@ + +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()); + } +} \ No newline at end of file diff --git a/w3/实验报告 b/w3/实验报告 new file mode 100644 index 0000000..be04d49 --- /dev/null +++ b/w3/实验报告 @@ -0,0 +1,23 @@ +一、核心代码 +【文件夹内】 +二、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 逐行检查代码,对照实验要求修正,确保每一项都符合评分标准。 \ No newline at end of file diff --git a/w3/类图.png b/w3/类图.png new file mode 100644 index 0000000..cf5bb48 Binary files /dev/null and b/w3/类图.png differ diff --git a/w3/运行结果.png b/w3/运行结果.png new file mode 100644 index 0000000..4242725 Binary files /dev/null and b/w3/运行结果.png differ