
在Java中,当我们将Scanner对象的创建和输入操作(如myObj.nextInt())直接放置在类的成员变量声明处或实例初始化块(即 {} 包裹的代码块)中时,每次创建该类的新实例时,这些代码都会被执行。这与许多初学者预期的行为(只执行一次)大相径庭。
考虑以下示例代码片段:
public class MyClass {
// 成员变量声明时进行初始化,并执行I/O
Scanner myObj = new Scanner(System.in);
{System.out.print("Enter a value: ");} // 实例初始化块
int value = myObj.nextInt(); // 每次创建对象都会执行此行
public static void main(String[] args) {
MyClass a = new MyClass(); // 第一次执行I/O
MyClass b = new MyClass(); // 第二次执行I/O
MyClass c = new MyClass(); // 第三次执行I/O
// ... 后续操作
}
}当main方法中执行new MyClass()时,Java虚拟机(JVM)会执行以下步骤来初始化一个新对象:
因此,如果main方法中创建了三个MyClass实例(如new MyClass();三次),那么上述的Scanner创建、提示信息打印和nextInt()操作将分别执行三次,导致用户需要输入三次值,这显然不是我们期望的单次输入行为。这种做法不仅会导致重复输入,还可能造成Scanner资源泄露(因为创建了多个Scanner但没有关闭)。
立即学习“Java免费学习笔记(深入)”;
解决上述问题的关键在于理解并正确使用Java的构造器(Constructor)。构造器是一种特殊的方法,用于在创建对象时初始化对象的实例变量。它是设置对象初始状态的理想场所。
将输入逻辑放置在构造器中,可以确保:
对于Scanner对象,最佳实践是:
下面是一个根据上述原则优化后的Java代码示例,它演示了如何正确使用Scanner和构造器来避免重复输入,并进行单位转换计算:
import java.util.Scanner;
public class Test {
// 1. 声明成员变量,但不在此处进行I/O操作或复杂初始化
int caratValue;
double gramsPerCarat;
double caratsInGrams;
double gramsInMilligrams;
double milligramsInPounds;
// 2. 定义构造器,用于初始化对象并执行输入、计算和(可选)输出
// 构造器接受一个Scanner对象作为参数,避免重复创建Scanner
public Test(Scanner scanner) {
// 提示用户输入,并通过传入的Scanner获取值
System.out.print("Enter Carat Value: ");
this.caratValue = scanner.nextInt(); // 将输入的值赋给成员变量
// 初始化常量和执行计算
this.gramsPerCarat = 0.20;
this.caratsInGrams = this.caratValue * this.gramsPerCarat;
this.gramsInMilligrams = this.caratsInGrams * 1000;
this.milligramsInPounds = this.gramsInMilligrams * 0.00220462 / 1000; // 注意:0.00220462 lbs/gram, 1000 mg/gram
// 在构造器中直接输出结果,或提供getter方法在main方法中输出
System.out.println("Carats in Grams: " + this.caratsInGrams);
System.out.println("Grams in Milligrams: " + this.gramsInMilligrams);
System.out.println("Milligrams in Pounds: " + this.milligramsInPounds);
}
// 如果需要从外部获取计算结果,可以提供getter方法
public double getCaratsInGrams() {
return caratsInGrams;
}
public double getGramsInMilligrams() {
return gramsInMilligrams;
}
public double getMilligramsInPounds() {
return milligramsInPounds;
}
// 3. 主方法:程序的入口点
public static void main(String[] args) {
// 在main方法中只创建一次Scanner对象
Scanner mainScanner = new Scanner(System.in);
// 创建Test类的实例,并将唯一的Scanner对象传递给其构造器
// 此时,构造器中的输入和计算逻辑只会被执行一次
Test conversionData = new Test(mainScanner);
// 如果构造器中没有直接输出,可以在这里通过getter方法获取并输出
// System.out.println("Carats in Grams (from getter): " + conversionData.getCaratsInGrams());
// System.out.println("Grams in Milligrams (from getter): " + conversionData.getGramsInMilligrams());
// System.out.println("Milligrams in Pounds (from getter): " + conversionData.getMilligramsInPounds());
// 使用完毕后,关闭Scanner以释放系统资源
mainScanner.close();
}
}Scanner的生命周期管理:
职责分离:
static关键字的考量:
代码可读性和维护性:
通过遵循这些原则,您可以编写出更健壮、更易于理解和维护的Java应用程序。
以上就是Java中Scanner的规范使用:理解对象初始化与构造器的应用的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号