0

0

Java中Scanner与对象实例化:避免重复输入和提升代码结构

心靈之曲

心靈之曲

发布时间:2025-07-10 21:24:02

|

830人浏览过

|

来源于php中文网

原创

java中scanner与对象实例化:避免重复输入和提升代码结构

本文旨在探讨在Java中将Scanner对象和输入逻辑放置在类字段初始化器中时,因多次创建对象而导致重复输入的问题。文章将详细阐述其原因,并提供最佳实践,包括使用构造方法进行对象初始化、合理管理Scanner的生命周期,以及区分实例初始化与静态初始化的重要性,从而帮助开发者编写更健壮、可维护的代码。

1. 问题背景:实例初始化与重复输入

在Java中,直接在类定义中声明并初始化非static的字段(也称为实例初始化器或字段初始化器),或者使用实例初始化块({}代码块),这些代码会在每次创建该类的新实例时执行。当Scanner对象的创建和输入操作被放置在这些位置时,就会导致每次实例化对象时都重复进行输入提示。

考虑以下示例代码,它展示了这种常见的问题模式:

package galitkami;

import java.util.Scanner;

public class test {

    Scanner myObj = new Scanner(System.in); // 实例字段初始化
    {System.out.print("Enter Carat Value: ");} // 实例初始化块
    int c = myObj.nextInt(); // 实例字段初始化,执行输入

    double g = 0.20;
    double cg = c*g;
    double gm = cg*1000;
    double mg = gm*0.00220462/1000;

    public static void main(String[] args) {
        test a = new test(); // 第一次实例化,执行一次输入
        test b = new test(); // 第二次实例化,执行第二次输入
        test c = new test(); // 第三次实例化,执行第三次输入

        System.out.println("Carats in Grams: "+a.cg);
        System.out.println("Grams in Milligrams: "+b.gm);
        System.out.println("Milligrams in Pounds: "+c.mg);
    }
}

在上述代码中,Scanner myObj = new Scanner(System.in);、{System.out.print("Enter Carat Value: ");} 和 int c = myObj.nextInt(); 都属于实例初始化的一部分。当main方法中执行new test()三次时,这些初始化逻辑会被重复执行三次,从而导致程序三次提示用户输入。这不仅造成了不必要的重复操作,也违背了程序设计的直观逻辑。

2. 最佳实践:使用构造方法与合理管理Scanner

为了解决上述问题并遵循良好的编程实践,我们应该将对象的初始化逻辑,特别是涉及用户输入和资源(如Scanner)管理的逻辑,放置在更合适的位置。

立即学习Java免费学习笔记(深入)”;

2.1 构造方法(Constructor)的应用

构造方法是Java中用于初始化新创建对象状态的特殊方法。它是执行对象创建后立即运行的代码块,是设置对象初始属性值的理想场所。通过将输入逻辑放入构造方法,我们可以更精确地控制何时进行输入。

Videoleap
Videoleap

Videoleap是一个一体化的视频编辑平台

下载
import java.util.Scanner;

public class Test { // 建议类名首字母大写

    // 声明类属性,但不在此处初始化,等待构造方法或特定方法进行初始化
    int c;
    double g, cg, gm, mg;

    // 类构造方法:用于初始化Test对象
    // 接受一个Scanner对象作为参数,避免在构造方法内部重复创建Scanner
    public Test(Scanner myObj) {
        System.out.print("Enter Carat Value: ");
        c = myObj.nextInt(); // 在构造方法中获取输入

        // 根据输入值计算其他属性
        g = 0.20;
        cg = c * g;
        gm = cg * 1000;
        mg = gm * 0.00220462 / 1000;

        // 可以在构造方法中直接打印结果,或者在main方法中访问对象属性后打印
        System.out.println("Carats in Grams: " + cg);
        System.out.println("Grams in Milligrams: " + gm);
        System.out.println("Milligrams in Pounds: " + mg);
    }

    public static void main(String[] args) {
        // 在main方法中创建并管理唯一的Scanner实例
        Scanner myObj = new Scanner(System.in);

        // 通过调用构造方法创建Test对象,此时构造方法中的逻辑(包括输入)会被执行
        // 如果只需要一次输入并计算,只需创建一个Test对象
        new Test(myObj); // 创建一个Test对象并执行其构造方法

        // 如果需要创建多个Test对象,且每个对象都需要独立输入,则可以多次调用构造方法
        // Test test1 = new Test(myObj);
        // Test test2 = new Test(myObj); // 这将再次提示输入

        // 重要:使用完毕后关闭Scanner,释放系统资源
        myObj.close();
    }
}

代码解释:

  • 属性声明与初始化分离: 类字段c, g, cg, gm, mg 仅被声明,它们的赋值操作被移到了构造方法中。
  • 构造方法参数: Test(Scanner myObj) 构造方法接受一个Scanner实例作为参数。这意味着Scanner对象是在main方法中创建并管理的,确保了只有一个Scanner实例用于整个程序的输入。
  • 输入与计算逻辑: 用户输入和基于输入进行计算的逻辑都被封装在构造方法中。当main方法中调用new Test(myObj)时,这些逻辑只执行一次。
  • 资源管理: Scanner对象在main方法中创建,并在使用完毕后通过myObj.close()关闭,这是良好的资源管理习惯,避免资源泄露。

2.2 静态Scanner的考量

在某些情况下,如果确实需要Scanner在整个应用程序生命周期内只被初始化一次,并且其输入不与特定对象实例绑定,可以将其声明为static。

import java.util.Scanner;

public class TestStaticScanner {

    static Scanner myObj = new Scanner(System.in); // 静态字段初始化,只执行一次
    // 静态初始化块,只在类加载时执行一次
    static {
        System.out.print("Enter Carat Value (Static): ");
    }
    final int c = myObj.nextInt(); // 实例字段初始化,但myObj已在静态初始化时准备好

    double g = 0.20;
    double cg = c * g;
    double gm = cg * 1000;
    double mg = gm * 0.00220462 / 1000;

    public static void main(String[] args) {
        // 即使创建多个TestStaticScanner对象,输入也只发生一次
        TestStaticScanner a = new TestStaticScanner();
        TestStaticScanner b = new TestStaticScanner(); // 不会再次提示输入
        TestStaticScanner c = new TestStaticScanner(); // 不会再次提示输入

        System.out.println("Carats in Grams: " + a.cg);
        System.out.println("Grams in Milligrams: " + a.gm);
        System.out.println("Milligrams in Pounds: " + a.mg);

        myObj.close(); // 关闭静态Scanner
    }
}

注意:

  • static的特性: static成员属于类本身,而不是类的某个实例。static字段和static初始化块只在类加载到JVM时执行一次。因此,即使创建多个TestStaticScanner对象,myObj和nextInt()也只被调用一次。
  • 局限性: 这种方法虽然解决了重复输入的问题,但它意味着所有TestStaticScanner实例都将共享同一个c值(因为c在第一个实例被创建时就已经确定),这可能不符合每个对象需要独立输入的场景。如果每个对象需要不同的输入,则构造方法是更优的选择。
  • final关键字: 在final int c = myObj.nextInt();中,final确保c一旦被赋值就不能更改。

3. 总结与最佳实践建议

为了编写健壮、可维护的Java代码,请遵循以下建议:

  1. 避免在实例初始化器中执行I/O操作: 避免将Scanner的创建、输入提示或数据读取等操作直接放在非static的字段初始化或实例初始化块中。这些代码会在每次创建对象时执行,容易导致意外行为。
  2. 使用构造方法进行对象初始化: 将对象状态的初始化逻辑(包括获取用户输入来设置初始值)封装在构造方法中。这样可以清晰地控制对象创建时的行为。
  3. 统一管理Scanner实例: 最好在程序的入口点(如main方法)创建并管理一个Scanner实例。如果需要将Scanner传递给其他方法或构造方法,通过参数传递,而不是在每个需要输入的地方都创建新的Scanner。
  4. 关闭Scanner资源: 在Scanner使用完毕后,务必调用close()方法关闭它,释放底层系统资源(如输入流)。这通常在main方法的末尾或使用try-with-resources语句完成。
  5. 理解static与实例成员的区别 static成员属于类,只加载一次;实例成员属于对象,每次创建对象时都会初始化。根据需求选择合适的修饰符。

通过采纳这些实践,您可以有效地管理Java中的输入流,避免常见的陷阱,并构建结构更清晰、行为更可预测的应用程序。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

186

2023.09.27

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

483

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

545

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

113

2025.08.29

C++中int的含义
C++中int的含义

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

200

2025.08.29

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

9

2026.01.30

c++ 字符串格式化
c++ 字符串格式化

本专题整合了c++字符串格式化用法、输出技巧、实践等等内容,阅读专题下面的文章了解更多详细内容。

9

2026.01.30

java 字符串格式化
java 字符串格式化

本专题整合了java如何进行字符串格式化相关教程、使用解析、方法详解等等内容。阅读专题下面的文章了解更多详细教程。

10

2026.01.30

python 字符串格式化
python 字符串格式化

本专题整合了python字符串格式化教程、实践、方法、进阶等等相关内容,阅读专题下面的文章了解更多详细操作。

3

2026.01.30

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

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

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