
本文深入探讨了java中因构造器职责混淆导致的无限循环问题。通过分析一个实际案例,揭示了在父类构造器中包含用户输入和子类实例化逻辑,并通过 `super()` 调用形成递归的机制。文章提供了将输入逻辑从构造器中分离的解决方案,并强调了构造器单一职责、分离关注点以及健壮的输入处理等java编程最佳实践,旨在帮助开发者构建更清晰、可维护的代码。
在提供的Java代码中,开发者遇到了一个意外的“循环”现象:即使只输入一次选择,程序却反复显示“[1]AGENT”和“[2]CUSTOMER”的提示。
仔细分析代码可以发现问题的根源:
这种“循环”并非由显式的 for 或 while 循环引起,而是由构造器之间的递归调用所致。
问题的根本原因在于 Person 类的构造器承担了过多的职责。构造器的主要作用是初始化对象的状态,确保对象在创建后处于一个有效且一致的状态。然而,在示例代码中,Person 构造器不仅初始化了属性,还包含了:
立即学习“Java免费学习笔记(深入)”;
当这些复杂的逻辑被放置在构造器中时,特别是当子类构造器又调用父类构造器时,很容易导致意料之外的行为,例如本例中的无限递归。这违反了软件设计中的“单一职责原则”(Single Responsibility Principle)。
解决此问题的核心思想是将用户交互和基于用户选择的对象创建逻辑从构造器中分离出来,让构造器回归其初始化对象状态的本职。
以下是修改后的代码,展示了如何将输入逻辑从构造器中分离:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner; // 确保 Scanner 被正确导入
// Person 类,构造器仅用于初始化属性
class Person {
protected String agentId;
protected String password;
protected String address;
public Person(String agentId, String password, String address) {
this.agentId = agentId;
this.password = password;
this.address = address;
// 构造器中不再包含用户输入逻辑
}
// 可以添加 getter/setter 方法
}
// Agent 类,构造器仅用于初始化属性
class Agent extends Person {
public Agent(String agentId, String password, String address) {
super(agentId, password, address);
// 代理登录和操作逻辑应在对象创建后调用,而不是构造器内
}
// 登录方法
public boolean login(int id, int pass) {
return id == 20860132 && pass == 20020729;
}
// 代理操作菜单
public void showAgentMenu(Scanner input) {
System.out.println("[1]ADD CAR");
System.out.println("[2]SCHEDULE");
System.out.println("[3]RECORDS");
System.out.print("Enter your choice: ");
int choice2 = input.nextInt();
input.nextLine(); // 消费掉换行符
switch (choice2) {
case 1:
addCarWorkflow(input);
break;
case 2:
System.out.print("Enter schedule details: ");
String scheduleDetails = input.nextLine();
schedule(scheduleDetails);
System.out.println("Schedule added.");
break;
case 3:
System.out.print("Enter record details: ");
String recordDetails = input.nextLine();
records(recordDetails);
System.out.println("Record added.");
break;
default:
System.out.println("Invalid choice.");
}
}
// 添加汽车流程
private void addCarWorkflow(Scanner input) {
boolean stopFlag = false;
List<String> cars = new ArrayList<>();
cars.add("Tayota");
cars.add("Hillux");
cars.add("Bugatti");
do {
System.out.println("[Current Cars]: " + cars);
System.out.print("Enter Car to add: ");
String car = input.nextLine();
cars.add(car);
addCar(cars); // 将当前列表写入文件
System.out.println("Would you like to add more?");
System.out.println("[1]YES");
System.out.println("[2]NO");
System.out.print("Enter your choice: ");
String choice3 = input.nextLine(); // 注意这里是 String
if (!choice3.equals("1")) { // 比较字符串
stopFlag = true;
}
} while (!stopFlag);
}
public void addCar(List<String> cars) {
try (FileWriter fw = new FileWriter("cars.txt", true);
PrintWriter pw = new PrintWriter(fw)) {
pw.println(cars);
} catch (IOException e) {
e.printStackTrace();
}
}
public void schedule(String schedule) {
try (FileWriter fw = new FileWriter("schedule.txt", true);
PrintWriter pw = new PrintWriter(fw)) {
pw.println(schedule);
} catch (IOException e) {
e.printStackTrace();
}
}
public void records(String record) {
try (FileWriter fw = new FileWriter("records.txt", true);
PrintWriter pw = new PrintWriter(fw)) {
pw.println(record);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// Customer 类,构造器仅用于初始化属性
class Customer extends Person {
private String customerId;
public Customer(String agentId, String password, String address, String customerId) {
super(agentId, password, address);
this.customerId = customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
public String getCustomerId() {
return customerId;
}
// 客户操作菜单
public void showCustomerMenu(Scanner input) {
System.out.println("[1]RENT CAR");
System.out.println("[2]VIEW SCHEDULE");
System.out.println("[3]EXTEND RENTAL");
System.out.print("Enter your choice: ");
int choice2 = input.nextInt();
input.nextLine(); // 消费掉换行符
switch (choice2) {
case 1:
System.out.print("Enter car to rent: ");
String carToRent = input.nextLine();
rentCar(carToRent);
System.out.println("Car rented.");
break;
case 2:
System.out.print("Enter schedule to view: ");
String scheduleToView = input.nextLine();
viewSchedule(scheduleToView);
System.out.println("Schedule viewed.");
break;
case 3:
System.out.print("Enter record to extend: ");
String recordToExtend = input.nextLine();
extend(recordToExtend);
System.out.println("Rental extended.");
break;
default:
System.out.println("Invalid choice.");
}
}
public void rentCar(String car) {
try (FileWriter fw = new FileWriter("rented_cars.txt", true); // 使用不同的文件名
PrintWriter pw = new PrintWriter(fw)) {
pw.println(car);
} catch (IOException e) {
e.printStackTrace();
}
}
public void viewSchedule(String schedule) {
try (FileWriter fw = new FileWriter("viewed_schedules.txt", true); // 使用不同的文件名
PrintWriter pw = new PrintWriter(fw)) {
pw.println(schedule);
} catch (IOException e) {
e.printStackTrace();
}
}
public void extend(String record) {
try (FileWriter fw = new FileWriter("extended_records.txt", true); // 使用不同的文件名
PrintWriter pw = new PrintWriter(fw)) {
pw.println(record);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 主类,包含 main 方法
public class Finals {
public static void main(String[] args) {
Scanner input = new Scanner(System.in); // 在 main 方法中创建 Scanner
System.out.println("[1]AGENT");
System.out.println("[2]CUSTOMER");
System.out.print("Enter your choice: ");
int choice = input.nextInt();
input.nextLine(); // 消费掉 nextInt() 留下的换行符
Person user = null; // 定义一个 Person 引用
if (choice == 1) {
// 代理登录流程
System.out.println("[AGENT LOGIN]");
System.out.print("ENTER AGENT ID:");
int id = input.nextInt();
input.nextLine(); // 消费掉换行符
System.out.print("ENTER PASSWORD:");
int pass = input.nextInt();
input.nextLine(); // 消费掉换行符
Agent agent = new Agent("20860132", "h208f32", "San luis"); // 创建 Agent 对象
if (agent.login(id, pass)) {
System.out.println("Login successful!");
user = agent; // 将 agent 赋值给 user
((Agent)user).showAgentMenu(input); // 显示代理菜单
} else {
System.out.println("INCORRECT PLEASE TRY AGAIN.");
}
} else if (choice == 2) {
// 客户流程 (此处仅为示例,可根据需求添加客户登录/注册逻辑)
System.out.println("[CUSTOMER SECTION]");
// 假设直接创建一个客户对象,或者通过某种方式获取客户ID
Customer customer = new Customer("defaultAgentId", "defaultPassword", "defaultAddress", "CUST001");
user = customer; // 将 customer 赋值给 user
((Customer)user).showCustomerMenu(input); // 显示客户菜单
} else {
System.out.println("Invalid choice. Exiting.");
}
input.close(); // 关闭 Scanner
}
}此次问题及解决方案引出了几个重要的Java编程最佳实践:
本教程通过一个具体的Java代码案例,详细阐述了因构造器职责混淆导致的递归调用和无限循环问题。核心解决方案在于将用户交互和对象创建的决策逻辑从构造器中剥离,使其专注于对象初始化。通过遵循构造器单一职责、分离关注点等编程最佳实践,并注意输入处理的细节,开发者可以构建出更加健壮、可维护且易于理解的Java应用程序。
以上就是Java构造器循环调用陷阱与解决方案的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号