
在java开发中,初学者常会在控制流结构(如do-while循环和switch语句)以及面向对象特性(如继承和构造器)的使用上遇到挑战。本文将深入探讨两个常见的错误场景:变量作用域问题导致的cannot find symbol错误,以及继承中子类构造器调用父类构造器不当导致的constructor cannot be applied错误,并提供详细的解决方案和优化建议。
在使用do-while循环时,一个常见的错误是将循环控制变量声明在do块内部。由于Java的作用域规则,在代码块({})内部声明的变量,其生命周期和可见性仅限于该代码块。这意味着,如果choice变量在do块内部声明,那么while条件语句就无法访问它,从而导致cannot find symbol编译错误。
错误示例分析:
do {
// ...
Scanner input = new Scanner(System.in);
int choice = input.nextInt(); // choice 在 do 块内部声明
// ...
} while (choice != 0); // 错误:choice 在此处不可见解决方案: 要解决这个问题,只需将循环控制变量(例如choice)的声明移到do-while循环的外部。这样,choice就拥有了更广的作用域,可以在整个do-while结构中被访问和修改。同时,Scanner对象也应在循环外部创建一次,以避免不必要的资源开销和潜在的资源泄漏。
修正后的代码片段(Main类):
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in); // Scanner 在循环外部声明一次
int choice; // choice 声明在 do-while 循环外部
do {
System.out.println("\nWhat size dog do you want to get!:\n" +
"1) small\n" + "2) medium\n" + "3) large\n" + "0) quit\n" +
"and any other number for non dog options!");
choice = input.nextInt(); // 在循环内部读取用户输入
switch (choice) {
case 1:
// ... 处理小型犬逻辑 ...
break;
case 2:
// ... 处理中型犬逻辑 ...
break;
case 3:
// ... 处理大型犬逻辑 ...
break;
case 0:
// 用户选择退出,无需额外操作,循环条件会处理
break;
default:
System.out.println("We are only giving dogs up for adoption today!");
}
} while (choice != 0); // choice 在此处可见
System.out.println("Goodbye\n");
input.close(); // 关闭 Scanner 资源
}
}在Java的继承体系中,子类构造器在执行前必须先调用其父类的构造器。这是因为子类会继承父类的成员变量,而这些成员变量的初始化通常由父类的构造器负责。如果子类构造器没有显式调用父类构造器,编译器会尝试插入一个默认的无参父类构造器调用(super())。然而,如果父类只定义了带参数的构造器而没有无参构造器,就会导致constructor Animal in class Animal cannot be applied to given types的编译错误。
立即学习“Java免费学习笔记(深入)”;
此外,子类不应重复声明父类中已经存在的成员变量。子类通过继承自动拥有父类的公共和受保护成员。如果子类再次声明同名成员,会造成“隐藏”父类成员的现象,这通常不是期望的行为,且会增加代码的复杂性和出错的可能性。
错误示例分析:
Animal 类:
public class Animal {
private String name;
private Integer age;
private String breed;
private String behavior;
public Animal(String name, Integer age, String breed, String behavior) {
this.name = name;
this.age = age;
this.breed = breed;
this.behavior = behavior;
}
// ... 其他方法 ...
}Dog 类(错误):
public class Dog extends Animal{
// 冗余地重复声明了父类已有的成员变量
public String name;
public int age;
public String breed;
public String behavior;
public Dog(String name, Integer age, String breed, String behavior) {
// 没有调用父类构造器,且试图重新初始化父类已有的成员
this.name = name;
this.age = age;
this.breed = breed;
this.behavior = behavior;
}
}解决方案:
修正后的代码片段(Dog类):
public class Dog extends Animal {
// 无需在此重复声明 name, age, breed, behavior 等父类已有的成员变量
// 如果 Dog 类有 Animal 类没有的特有属性,则在此声明。
public Dog(String name, Integer age, String breed, String behavior) {
super(name, age, breed, behavior); // 显式调用父类 Animal 的构造器
}
// ... Dog 类特有的方法或属性 ...
}根据用户需求,“如果用户输入5表示同意领养,则显示再见消息;如果输入6或更高,则循环返回主菜单。”这要求我们对程序的控制流进行更精细的设计。原始的do-while (choice != 0)只处理了0退出,没有考虑到5的退出逻辑。
优化思路:
修正后的Main类代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int choice; // 主菜单选择
final int QUIT_OPTION = 0;
final int ADOPT_OPTION = 5;
final int NO_ADOPT_OPTION_MIN = 6;
do {
System.out.println("\nWhat size dog do you want to get!:\n" +
"1) small\n" + "2) medium\n" + "3) large\n" +
QUIT_OPTION + ") quit\n" +
"and any other number for non dog options!");
choice = input.nextInt();
switch (choice) {
case 1:
System.out.println("We have one small breeded dog. A Chihuahua is up for adoption!");
System.out.println("\nHere is more information!");
Chihuahua goliath = new Chihuahua("Goliath", 4, "Chihuahua", "aggressive");
goliath.printDogInfo();
System.out.println("\nTo take me home press " + ADOPT_OPTION + ", or " + NO_ADOPT_OPTION_MIN + " or higher for no!");
int takeHomeChoice1 = input.nextInt();
if (takeHomeChoice1 == ADOPT_OPTION) {
choice = ADOPT_OPTION; // 设置 choice 为 5,使主循环终止
}
// 如果 takeHomeChoice1 >= 6,choice 保持不变,主循环会继续
break;
case 2:
System.out.println("We have one medium breeded dog. A Labrador is up for adoption!");
System.out.println("\nHere is more information!");
Labrador hendrix = new Labrador("Hendrix", 8, "Labrador", "not aggressive");
hendrix.printDogInfo();
System.out.println("\nTo take me home press " + ADOPT_OPTION + ", or " + NO_ADOPT_OPTION_MIN + " or higher for no!");
int takeHomeChoice2 = input.nextInt();
if (takeHomeChoice2 == ADOPT_OPTION) {
choice = ADOPT_OPTION;
}
break;
case 3:
System.out.println("We have one large breeded dog. A Great dane is up for adoption!");
System.out.println("\nHere is more information!");
Greatdane toodles = new Greatdane("Toodles", 2, "Greatdane", "not aggressive");
toodles.printDogInfo();
System.out.println("\nTo take me home press " + ADOPT_OPTION + ", or " + NO_ADOPT_OPTION_MIN + " or higher for no!");
int takeHomeChoice3 = input.nextInt();
if (takeHomeChoice3 == ADOPT_OPTION) {
choice = ADOPT_OPTION;
}
break;
case QUIT_OPTION:
// 用户直接选择退出,choice 已经是 0,循环条件会处理
break;
default:
System.out.println("We are only giving dogs up for adoption today!");
// 其他无效输入,循环继续
}
} while (choice != QUIT_OPTION && choice != ADOPT_OPTION); // 循环直到选择退出 (0) 或领养 (5)
System.out.println("\nGoodbye!"); // 统一的退出消息
input.close(); // 关闭 Scanner 资源
}
}注意事项与总结:
通过遵循这些原则,您可以编写出更健壮、更易于理解和维护的Java代码。
以上就是解决Java do-while 循环、switch 语句与继承中的常见错误的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号