Compare commits
No commits in common. 'main' and 'master' have entirely different histories.
@ -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 |
||||
@ -0,0 +1,10 @@ |
|||||
|
# 默认忽略的文件 |
||||
|
/shelf/ |
||||
|
/workspace.xml |
||||
|
# 已忽略包含查询文件的默认文件夹 |
||||
|
/queries/ |
||||
|
# Datasource local storage ignored files |
||||
|
/dataSources/ |
||||
|
/dataSources.local.xml |
||||
|
# 基于编辑器的 HTTP 客户端请求 |
||||
|
/httpRequests/ |
||||
@ -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> |
||||
@ -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> |
||||
@ -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> |
||||
@ -1,9 +0,0 @@ |
|||||
package w5基础版; |
|
||||
|
|
||||
// 圆
|
|
||||
public class Circle extends Shape { |
|
||||
@Override |
|
||||
public void draw() { |
|
||||
System.out.println("🔵 绘制圆形"); |
|
||||
} |
|
||||
} |
|
||||
@ -1,9 +0,0 @@ |
|||||
package w5基础版; |
|
||||
|
|
||||
// 矩形
|
|
||||
public class Rectangle extends Shape { |
|
||||
@Override |
|
||||
public void draw() { |
|
||||
System.out.println("🔲 绘制矩形"); |
|
||||
} |
|
||||
} |
|
||||
@ -1,9 +0,0 @@ |
|||||
package w5基础版; |
|
||||
|
|
||||
// 父类
|
|
||||
public class Shape { |
|
||||
// draw方法
|
|
||||
public void draw() { |
|
||||
System.out.println("绘制图形"); |
|
||||
} |
|
||||
} |
|
||||
@ -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(); |
|
||||
} |
|
||||
} |
|
||||
|
Before Width: | Height: | Size: 89 KiB |
@ -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); |
|
||||
} |
|
||||
} |
|
||||
@ -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() + " 是普通人员"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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; |
|
||||
} |
|
||||
} |
|
||||
@ -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; |
|
||||
} |
|
||||
} |
|
||||
@ -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(); |
|
||||
} |
|
||||
} |
|
||||
|
Before Width: | Height: | Size: 105 KiB |
@ -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 方法访问,保证封装性。 |
|
||||
@ -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"); |
|
||||
} |
|
||||
} |
|
||||
@ -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("⌨️ 键盘已关闭并断开"); |
|
||||
} |
|
||||
} |
|
||||
@ -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("🖱️ 鼠标已关闭并断开"); |
|
||||
} |
|
||||
} |
|
||||
@ -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); |
|
||||
} |
|
||||
} |
|
||||
@ -1,7 +0,0 @@ |
|||||
package w5进阶版; |
|
||||
|
|
||||
// USB接口
|
|
||||
public interface USB { |
|
||||
void open(); // 打开设备
|
|
||||
void close(); // 关闭设备
|
|
||||
} |
|
||||
|
Before Width: | Height: | Size: 116 KiB |
@ -1,9 +0,0 @@ |
|||||
# java |
|
||||
# 温度转换器 (Java 版) |
|
||||
|
|
||||
将 Python 温度转换程序移植为 Java,支持摄氏度与华氏度互转。 |
|
||||
实现了三种运行模式:交互式、命令行参数、批量文件处理。 |
|
||||
|
|
||||
## 编译 |
|
||||
```bash |
|
||||
javac 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 <文件名>"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
Before Width: | Height: | Size: 109 KiB |
@ -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("无有效数据"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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 ? "已出租" : "未出租"); |
|
||||
} |
|
||||
} |
|
||||
@ -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()); |
|
||||
} |
|
||||
} |
|
||||
@ -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 逐行检查代码,对照实验要求修正,确保每一项都符合评分标准。 |
|
||||
|
Before Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 183 KiB |
@ -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; |
|
||||
} |
|
||||
} |
|
||||
@ -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); |
|
||||
} |
|
||||
} |
|
||||
@ -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; |
|
||||
} |
|
||||
} |
|
||||
@ -1,4 +0,0 @@ |
|||||
public abstract class Shape { |
|
||||
// 抽象方法:所有图形必须实现面积计算
|
|
||||
public abstract double getArea(); |
|
||||
} |
|
||||
@ -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); |
|
||||
} |
|
||||
} |
|
||||
@ -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; |
|
||||
} |
|
||||
} |
|
||||
@ -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 关系且需要多态特性时,才考虑使用继承。 |
|
||||
@ -1,5 +0,0 @@ |
|||||
// 抽象类:Animal
|
|
||||
public abstract class Animal { |
|
||||
// 抽象方法:发出声音,子类必须重写
|
|
||||
public abstract void makeSound(); |
|
||||
} |
|
||||
@ -1,9 +0,0 @@ |
|||||
// Cat类:仅继承Animal,不实现Swimmable
|
|
||||
public class Cat extends Animal { |
|
||||
|
|
||||
// 重写父类抽象方法:发出叫声
|
|
||||
@Override |
|
||||
public void makeSound() { |
|
||||
System.out.println("喵喵喵!"); |
|
||||
} |
|
||||
} |
|
||||
@ -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("小狗在水里游泳~"); |
|
||||
} |
|
||||
} |
|
||||
@ -1,5 +0,0 @@ |
|||||
// 接口:Swimmable(可游泳的能力)
|
|
||||
public interface Swimmable { |
|
||||
// 抽象方法:游泳
|
|
||||
void swim(); |
|
||||
} |
|
||||
@ -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不会游泳"); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
Before Width: | Height: | Size: 218 KiB |