0

0

解决Java do-while 循环、switch 语句与继承中的常见错误

DDD

DDD

发布时间:2025-09-26 08:10:38

|

250人浏览过

|

来源于php中文网

原创

解决Java do-while 循环、switch 语句与继承中的常见错误

本教程旨在解决Java编程中在使用do-while循环与switch语句时常见的变量作用域问题,以及在继承体系中子类构造器调用父类构造器时易犯的错误。文章将通过具体代码示例,详细阐述如何正确处理变量声明、super()关键字的使用,并优化程序的用户交互逻辑,确保代码的健壮性和可读性。

java开发中,初学者常会在控制流结构(如do-while循环和switch语句)以及面向对象特性(如继承和构造器)的使用上遇到挑战。本文将深入探讨两个常见的错误场景:变量作用域问题导致的cannot find symbol错误,以及继承中子类构造器调用父类构造器不当导致的constructor cannot be applied错误,并提供详细的解决方案和优化建议。

1. 理解变量作用域与do-while循环

在使用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 资源
    }
}

2. Java继承中构造器的正确使用

在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 类(错误):

Figma
Figma

Figma 是一款基于云端的 UI 设计工具,可以在线进行产品原型、设计、评审、交付等工作。

下载
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;
    }
}

解决方案:

  1. 在子类构造器的第一行,使用super()关键字显式调用父类的构造器,并传入相应的参数来初始化父类的成员。
  2. 移除子类中与父类重复的成员变量声明。子类会自动继承这些成员。

修正后的代码片段(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 类特有的方法或属性 ...
}

3. 优化用户交互与程序控制流

根据用户需求,“如果用户输入5表示同意领养,则显示再见消息;如果输入6或更高,则循环返回主菜单。”这要求我们对程序的控制流进行更精细的设计。原始的do-while (choice != 0)只处理了0退出,没有考虑到5的退出逻辑。

优化思路:

  1. 主循环的退出条件应包含用户选择“退出”(0)和“领养”(5)两种情况。
  2. 在用户选择具体犬种(case 1, 2, 3)后,再提示用户是否领养,并根据用户的二次输入来更新主循环的控制变量。

修正后的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 资源
    }
}

注意事项与总结:

  • 变量作用域: 始终确保变量在需要访问它的代码块中声明,或者声明在更广阔的作用域中。
  • 继承与构造器: 子类构造器必须通过super()显式调用父类构造器来完成父类部分的初始化。避免在子类中重复声明父类已有的成员变量。
  • 程序控制流: 精心设计循环条件和内部逻辑,以准确反映用户的意图和程序的预期行为。对于复杂的交互,可以考虑使用嵌套循环或更复杂的条件判断。
  • 资源管理: 对于像Scanner这样的资源,在使用完毕后务必调用close()方法释放资源,避免资源泄漏。
  • 代码可读性 使用常量(final关键字)代替“魔术数字”(Magic Numbers),如QUIT_OPTION、ADOPT_OPTION,可以显著提高代码的可读性和可维护性。

通过遵循这些原则,您可以编写出更健壮、更易于理解和维护的Java代码。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1500

2023.10.24

switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

538

2023.09.21

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

422

2024.03.13

while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

94

2023.09.25

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

56

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

52

2025.11.27

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

469

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

13

2025.12.06

php中文乱码如何解决
php中文乱码如何解决

本文整理了php中文乱码如何解决及解决方法,阅读节专题下面的文章了解更多详细内容。

1

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.9万人学习

C# 教程
C# 教程

共94课时 | 7.8万人学习

Java 教程
Java 教程

共578课时 | 52.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号