Java实现:如何将父子类字段值共同存入LibraryItem类型的ArrayList
代码现存硬伤点
- 分隔符规则冲突:子类
readData里把分隔符设为[,\n],父类readData又改成\\s?,\\s?,两套规则切换时很容易出现切分错位,触发NoSuchElementException - 冗余代码无效:Library类的分支里提前给Scanner设置的分隔符,进到子类readData后会被覆盖,完全是无意义的重复操作
- 字段解析错位风险:当前父类、子类的读字段顺序,需要和CSV文件的列顺序严格对齐,一旦列顺序写错,会直接导致类型转换报错、字段值张冠李戴
- 有参构造赋值漏失:Book类的带参构造接收了
noOfPages、publisher两个父类字段值,但没有传给父类做赋值,走该构造路径时父类字段全是默认初始值
完整可运行的实现方案
1. 全局统一分隔符规则
把分隔符的设置逻辑前置到Library类创建Scanner的位置,只设置一次就全链路生效,所有readData方法里删掉重复的分隔符代码。
注意:必须用兼容逗号前后带空格的正则\\s*,\\s*,适配大部分CSV导出的格式
修改后的分支代码:
if (typeOfData.equals("Book")) { System.out.println(lineOfText); Scanner scanner2 = new Scanner(lineOfText); // 一次设置,后续读数据全程生效 scanner2.useDelimiter("\\s*,\\s*"); LibraryItem libraryItem = new Book(); libraryItem.readData(scanner2); storeItem(libraryItem); scanner2.close(); } else if (typeOfData.equals("Periodical")) { System.out.println(lineOfText); Scanner scanner2 = new Scanner(lineOfText); scanner2.useDelimiter("\\s*,\\s*"); LibraryItem libraryItem = new Periodical(); libraryItem.readData(scanner2); storeItem(libraryItem); scanner2.close(); }
2. 对齐解析顺序
严格按照「子类独有字段在前、父类公共字段在后」的逻辑写readData方法,保证和CSV列顺序完全匹配:
- 父类
LibraryItem的readData方法删掉分隔符设置,按固定顺序读公共字段即可:
public void readData(Scanner scanner2) { this.noOfPages = scanner2.nextInt(); this.publisher = scanner2.next().trim(); this.title = scanner2.next().trim(); this.itemCode = scanner2.next().trim(); this.cost = scanner2.nextInt(); this.timesBorrowed = scanner2.nextInt(); this.onLoan = scanner2.nextBoolean(); }
- Book类的readData方法,先读自身独有的author、isbn字段,再调用super读公共字段:
@Override public void readData(Scanner scanner2) { this.author = scanner2.next().trim(); this.isbn = scanner2.next().trim(); super.readData(scanner2); }
- Periodical类的readData方法,先读自身独有的publicationDate字段,再调用super读公共字段:
@Override public void readData(Scanner scanner2) { this.publicationDate = scanner2.next().trim(); super.readData(scanner2); }
注意:CSV文件里的列顺序必须和上面的读取顺序严格对应,比如Book行的列必须是「作者,ISBN,页数,出版社,书名,馆藏编号,成本,累计借阅次数,是否在借」,Periodical行的列必须是「出版日期,页数,出版社,书名,馆藏编号,成本,累计借阅次数,是否在借」,不然一定会读错
3. 补全构造的字段传递
给LibraryItem增加带所有公共字段的构造方法,修正子类构造漏传父类值的问题:
// LibraryItem 新增的全参构造 public LibraryItem(int noOfPages, String publisher, String title, String itemCode, int cost, int timesBorrowed, boolean onLoan) { this.noOfPages = noOfPages; this.publisher = publisher; this.title = title; this.itemCode = itemCode; this.cost = cost; this.timesBorrowed = timesBorrowed; this.onLoan = onLoan; }
子类构造调用对应的super方法,把所有值正确传递:
// Book 修正后的构造 public Book(String author, String isbn, int noOfPages, String publisher, String title, String itemCode, int cost, int timesBorrowed, boolean onLoan) { super(noOfPages, publisher, title, itemCode, cost, timesBorrowed, onLoan); this.author = author; this.isbn = isbn; } // Periodical 修正后的构造 public Periodical(String publicationDate, int noOfPages, String publisher, String title, String itemCode, int cost, int timesBorrowed, boolean onLoan) { super(noOfPages, publisher, title, itemCode, cost, timesBorrowed, onLoan); this.publicationDate = publicationDate; }
4. 增加基础容错
在Scanner读数据的外层加简单的异常捕获,遇到单条解析失败的行直接打印错误信息跳过,不要因为一行坏数据中断整个文件的读取流程。
内容的提问来源于stack exchange,提问作者The_Liner
相关产品推荐
相关产品推荐

