1) 基于以上代码,解决收支记录不能保存的问题。理解对象的序列化和持久化,熟悉对象流的读取和写入方法,掌握数组的声明和动态内存申请。 2) 初步设计将“保存记录”和“读取记录”功能集成到成员方法里。在FamilyAccount类的main方法中,原来的2个局部变量:基本金balance和收支明细details需要移至方法外,作为成员变量,方便各成员方法使用和共享。同时增加的成员变量还有:长度为100的数组用来存储收支记录;计数器用来计算目前收支记录数;文件名说明保存收支记录的位置。 3) FamilyAccount类增加“保存记录”方法,执行位置在用户确认退出系统后。思路:如果收支记录数发生变化,首先将收支记录数组依次放置到临时数组中,再调用写对象流方法,将临时数组写到文件里。在实验报告中详细描述此功能实现。 4) FamilyAccount类增加“读取记录”方法,执行位置在main方法菜单显示循环前。思路:如果存储收支记录的文件存在,首先调用读对象流方法,将数据读到临时数组中,再依次放置到收支记录数组中。在实验报告中详细描述此功能实现。 5) FamilyAccount类的main方法增加“放置记录”功能,执行位置在菜单2和3的收支明细details拼串完毕后。思路:将每一次收支记录包装为一维数组,然后依次放到收支记录数组里,计数器自加1。 6) 在实验过程中详细记录分析思路和操作步骤,包含文字、关键源码、图形、表格等。
时间: 2023-11-22 16:56:39 浏览: 69
绝对完整的计算器代码!!可以保存记录
1. 解决收支记录不能保存的问题
在原有代码基础上,我们需要进行以下修改:
1.1 增加成员变量和数组声明
我们需要在 Family 类中增加以下成员变量和声明:
```java
private double balance; // 基本金
private String details[][]; // 收支明细
private int count; // 记录数
private final String filename = "record.dat"; // 存储收支记录的文件名
```
其中,`balance` 是基本金,`details` 是收支明细的二维数组,`count` 是当前收支记录数,`filename` 是存储收支记录的文件名。
1.2 实现序列化和反序列化方法
我们需要为 `FamilyAccount` 类实现序列化和反序列化方法,以便将对象持久化到文件中和从文件中读取对象。
```java
public void save() {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
String[][] temp = new String[count][3];
for (int i = 0; i < count; i++) {
temp[i][0] = details[i][0];
temp[i][1] = details[i][1];
temp[i][2] = details[i][2];
}
oos.writeObject(temp);
} catch (IOException e) {
e.printStackTrace();
}
}
public void load() {
File file = new File(filename);
if (file.exists()) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file))) {
String[][] temp = (String[][]) ois.readObject();
for (int i = 0; i < temp.length; i++) {
details[i][0] = temp[i][0];
details[i][1] = temp[i][1];
details[i][2] = temp[i][2];
}
count = temp.length;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
```
`save` 方法将收支记录保存到文件中,`load` 方法从文件中读取收支记录。
1.3 修改菜单选项
在原有的菜单选项中增加一个保存记录的选项。
```java
System.out.println("-----------------家庭收支记账软件-----------------\n");
System.out.println("\t\t1 收支明细");
System.out.println("\t\t2 登记收入");
System.out.println("\t\t3 登记支出");
System.out.println("\t\t4 退 出");
System.out.println("\t\t5 保存记录");
System.out.print("\n\t请选择(1-5):");
```
1.4 在退出程序前保存记录
在用户选择退出程序时,我们需要调用 `save` 方法保存记录。
```java
while (loopFlag) {
choice = sc.nextInt();
switch (choice) {
case 1:
this.showDetails();
break;
case 2:
this.income();
break;
case 3:
this.spending();
break;
case 4:
System.out.print("确认是否退出(Y/N):");
char confirm = Utility.readConfirmSelection();
if (confirm == 'Y') {
loopFlag = false;
System.out.println("程序退出!");
this.save(); // 保存记录
}
break;
case 5:
this.save();
break;
default:
break;
}
}
```
2. 将“保存记录”和“读取记录”功能集成到成员方法里
我们需要将 `balance` 和 `details` 移至方法外,作为成员变量,方便各成员方法使用和共享。同时增加的成员变量还有:长度为100的数组用来存储收支记录;计数器用来计算目前收支记录数;文件名说明保存收支记录的位置。
2.1 增加成员变量和数组声明
我们需要在 `FamilyAccount` 类中增加以下成员变量和数组声明:
```java
private double balance; // 基本金
private String details[][]; // 收支明细
private int count; // 记录数
private final String filename = "record.dat"; // 存储收支记录的文件名
```
其中,`balance` 是基本金,`details` 是收支明细的二维数组,`count` 是当前收支记录数,`filename` 是存储收支记录的文件名。
2.2 修改方法
我们需要修改以下方法:
2.2.1 构造方法
在构造方法中,我们需要调用 `load` 方法读取收支记录。
```java
public FamilyAccount(double balance) {
this.balance = balance;
this.details = new String[100][3];
this.count = 0;
this.load(); // 读取收支记录
}
```
2.2.2 save 方法
我们已经在第一部分实现了 `save` 方法,无需再进行修改。
2.2.3 load 方法
我们已经在第一部分实现了 `load` 方法,无需再进行修改。
2.2.4 income 方法
在 `income` 方法中,我们需要增加一条收入记录,并将记录数加1。
```java
public void income() {
System.out.print("请输入收入金额:");
double money = sc.nextDouble();
System.out.print("请输入收入说明:");
String info = sc.next();
balance += money;
details[count][0] = "收入";
details[count][1] = String.valueOf(money);
details[count][2] = info;
count++;
System.out.println("---------------------登记完成---------------------\n");
}
```
2.2.5 spending 方法
在 `spending` 方法中,我们需要增加一条支出记录,并将记录数加1。
```java
public void spending() {
System.out.print("请输入支出金额:");
double money = sc.nextDouble();
System.out.print("请输入支出说明:");
String info = sc.next();
if (balance < money) {
System.out.println("支出超出账户额度,支付失败!");
return;
}
balance -= money;
details[count][0] = "支出";
details[count][1] = String.valueOf(money);
details[count][2] = info;
count++;
System.out.println("---------------------登记完成---------------------\n");
}
```
2.2.6 showDetails 方法
在 `showDetails` 方法中,我们需要遍历收支明细数组,输出每一条记录。
```java
public void showDetails() {
System.out.println("-----------------当前收支明细记录-----------------\n");
System.out.println("收支\t账户金额\t收支金额\t说 明");
for (int i = 0; i < count; i++) {
System.out.println(details[i][0] + "\t" + balance + "\t\t" + details[i][1] + "\t\t" + details[i][2]);
}
System.out.println("\n--------------------------------------------------\n");
}
```
2.2.7 save 方法
我们已经在第一部分实现了 `save` 方法,无需再进行修改。
2.2.8 load 方法
我们已经在第一部分实现了 `load` 方法,无需再进行修改。
2.3 修改 main 方法
在 `main` 方法中,我们需要调用 `FamilyAccount` 的构造方法初始化账户,并在退出程序前保存记录。
```java
public static void main(String[] args) {
FamilyAccount fa = new FamilyAccount(10000);
boolean loopFlag = true;
char choice;
Scanner sc = new Scanner(System.in);
while (loopFlag) {
System.out.println("-----------------家庭收支记账软件-----------------\n");
System.out.println("\t\t1 收支明细");
System.out.println("\t\t2 登记收入");
System.out.println("\t\t3 登记支出");
System.out.println("\t\t4 退 出");
System.out.println("\t\t5 保存记录");
System.out.print("\n\t请选择(1-5):");
choice = Utility.readMenuSelection();
switch (choice) {
case '1':
fa.showDetails();
break;
case '2':
fa.income();
break;
case '3':
fa.spending();
break;
case '4':
System.out.print("确认是否退出(Y/N):");
char confirm = Utility.readConfirmSelection();
if (confirm == 'Y') {
loopFlag = false;
System.out.println("程序退出!");
fa.save();
}
break;
case '5':
fa.save();
break;
default:
break;
}
}
}
```
3. 实现思路
在第一步中,我们需要将收支记录保存到文件中,并从文件中读取收支记录。我们使用了 Java 对象的序列化和反序列化方法。在保存记录时,我们将收支记录数组依次放置到临时数组中,然后调用写对象流方法,将临时数组写到文件里。在读取记录时,我们首先判断存储收支记录的文件是否存在,如果存在则调用读对象流方法,将数据读到临时数组中,再依次放置到收支记录数组中。
在第二步中,我们将 `balance` 和 `details` 移至方法外,作为成员变量,方便各成员方法使用和共享。同时增加的成员变量还有:长度为100的数组用来存储收支记录;计数器用来计算目前收支记录数;文件名说明保存收支记录的位置。我们还增加了一个构造方法,在创建 `FamilyAccount` 对象时,会调用 `load` 方法读取收支记录。
在第三步中,我们修改了菜单选项,在退出程序前保存记录。我们还实现了将每一次收支记录包装为一维数组,然后依次放到收支记录数组里,计数器自加1。
阅读全文