
本教程旨在指导java初学者在不使用数组和map的情况下,实现整数与罗马数字的相互转换。文章将详细解析转换逻辑,重点解决罗马数字转整数时常见的无限循环问题,并优化类的状态管理,确保数据一致性,提供一套完整且易于理解的解决方案。
在开始编程实现之前,我们首先需要明确本教程中罗马数字的转换规则。根据题目要求,我们不考虑罗马数字的减法规则(如IV=4, IX=9),而是采用简单的累加规则:
理解这些规则是正确实现转换的基础。
我们将创建一个名为 RomanNumeral 的Java类来封装罗马数字和整数之间的转换逻辑。该类将包含以下核心成员:
该类还应提供三个构造函数以支持不同的初始化方式:
立即学习“Java免费学习笔记(深入)”;
此外,还需提供 getter 和 setter 方法来访问和修改 romanNum 和 decimalNum。
将整数转换为罗马数字通常采用“贪婪算法”。我们从最大的罗马数字值开始,只要当前整数大于或等于该值,就将其对应的罗马数字字符添加到结果字符串中,并从整数中减去该值,直到整数为0。
以下是 convertIntegerToRoman 方法的实现:
public String convertIntegerToRoman(int r) {
int roman = r;
String finalRoman = "";
while (roman >= 1000) {
finalRoman = finalRoman + "M";
roman -= 1000;
}
while (roman >= 500) {
finalRoman = finalRoman + "D";
roman -= 500;
}
while (roman >= 100) {
finalRoman = finalRoman + "C";
roman -= 100;
}
while (roman >= 50) {
finalRoman = finalRoman + "L";
roman -= 50;
}
while (roman >= 10) {
finalRoman = finalRoman + "X";
roman -= 10;
}
while (roman >= 5) {
finalRoman = finalRoman + "V";
roman -= 5;
}
while (roman >= 1) {
finalRoman = finalRoman + "I";
roman -= 1;
}
return finalRoman;
}解析: 每个 while 循环负责处理一个特定的罗马数字值。例如,第一个 while (roman >= 1000) 会将所有可以表示为 'M' 的部分提取出来。由于我们从大到小处理,确保了正确的罗马数字顺序。
这是原代码中出现问题的部分。原始实现中,在一个 for 循环内部使用了多个 while 循环来检查 decimal.charAt(i)。问题在于,如果 decimal.charAt(i) 满足某个 while 循环的条件(例如是 'M'),那么 i 的值在 while 循环内部不会改变,导致该 while 循环无限执行,因为 decimal.charAt(i) 始终是 'M'。
解决方案: 将内部的 while 循环全部替换为 if 语句。for 循环会遍历罗马数字字符串的每一个字符,if 语句只会在当前字符匹配时执行一次加法操作,然后 for 循环会自动递增 i,处理下一个字符。
以下是 convertRomanToInteger 方法的修正版本:
private int convertRomanToInteger(String n) {
String roman = n; // 更名为roman以保持一致性
int finalDecimal = 0;
// 循环条件应为 i < roman.length(),避免索引越界
for (int i = 0; i < roman.length(); i++) {
char currentChar = roman.charAt(i); // 获取当前字符
if (currentChar == 'M') {
finalDecimal += 1000;
} else if (currentChar == 'D') { // 使用else if 提高效率,避免不必要的检查
finalDecimal += 500;
} else if (currentChar == 'C') {
finalDecimal += 100;
} else if (currentChar == 'L') {
finalDecimal += 50;
} else if (currentChar == 'X') {
finalDecimal += 10;
} else if (currentChar == 'V') {
finalDecimal += 5;
} else if (currentChar == 'I') {
finalDecimal += 1;
}
// 如果字符不属于任何已知的罗马数字,可以考虑抛出异常或进行错误处理
}
return finalDecimal;
}解析:
原始的 setRomanNumeral 和 setDecimalNumeral 方法只更新了其对应的私有字段,而没有更新另一个字段。这会导致 RomanNumeral 对象处于不一致的状态。例如,如果调用 setRomanNumeral("X"),romanNum 会变为 "X",但 decimalNum 仍然是旧值。
为了保持对象状态的一致性,每当一个值被设置时,另一个值也应该通过转换方法进行更新。
以下是优化后的 setter 方法:
public void setRomanNumeral(String r) {
this.romanNum = r;
this.decimalNum = convertRomanToInteger(r); // 更新对应的整数值
}
public void setDecimalNumeral(int i) {
this.decimalNum = i;
this.romanNum = convertIntegerToRoman(i); // 更新对应的罗马数字字符串
}解析: 通过在 setter 方法中调用相应的转换逻辑,我们保证了 romanNum 和 decimalNum 始终保持同步,反映同一数值的不同表示形式。
结合上述所有修正和优化,以下是完整的 RomanNumeral 类代码:
package jfauvelle_G10_A04; // 根据实际包名调整
public class RomanNumeral {
private String romanNum = "";
private int decimalNum = 0;
// 默认构造函数
public RomanNumeral() {
this.romanNum = "";
this.decimalNum = 0;
}
// 字符串构造函数
public RomanNumeral(String r) {
this.romanNum = r;
this.decimalNum = convertRomanToInteger(r);
}
// 整数构造函数
public RomanNumeral(int i) {
this.decimalNum = i;
this.romanNum = convertIntegerToRoman(i);
}
// Setter for Roman Numeral
public void setRomanNumeral(String r) {
this.romanNum = r;
this.decimalNum = convertRomanToInteger(r); // 确保状态一致性
}
// Getter for Roman Numeral
public String getRomanNumeral() {
return romanNum;
}
// Setter for Decimal Numeral
public void setDecimalNumeral(int i) {
this.decimalNum = i;
this.romanNum = convertIntegerToRoman(i); // 确保状态一致性
}
// Getter for Decimal Numeral
public int getDecimalNumeral() {
return decimalNum;
}
// 整数到罗马数字的转换方法
public String convertIntegerToRoman(int r) {
int roman = r;
String finalRoman = "";
while (roman >= 1000) { finalRoman += "M"; roman -= 1000; }
while (roman >= 500) { finalRoman += "D"; roman -= 500; }
while (roman >= 100) { finalRoman += "C"; roman -= 100; }
while (roman >= 50) { finalRoman += "L"; roman -= 50; }
while (roman >= 10) { finalRoman += "X"; roman -= 10; }
while (roman >= 5) { finalRoman += "V"; roman -= 5; }
while (roman >= 1) { finalRoman += "I"; roman -= 1; }
return finalRoman;
}
// 罗马数字到整数的转换方法 (修正版)
private int convertRomanToInteger(String n) {
String roman = n;
int finalDecimal = 0;
for (int i = 0; i < roman.length(); i++) {
char currentChar = roman.charAt(i);
if (currentChar == 'M') {
finalDecimal += 1000;
} else if (currentChar == 'D') {
finalDecimal += 500;
} else if (currentChar == 'C') {
finalDecimal += 100;
} else if (currentChar == 'L') {
finalDecimal += 50;
} else if (currentChar == 'X') {
finalDecimal += 10;
} else if (currentChar == 'V') {
finalDecimal += 5;
} else if (currentChar == 'I') {
finalDecimal += 1;
}
}
return finalDecimal;
}
}为了验证 RomanNumeral 类的功能和修正是否正确,可以使用一个 main 方法进行测试。以下是原始测试用例的稍作修改,以更好地反映状态一致性检查:
public class RomanNumeralCalculatorTestCase {
public static void main(String[] args) {
boolean working = true;
// 测试默认构造函数和Setter
RomanNumeral case1 = new RomanNumeral();
case1.setRomanNumeral("XVI"); // 设置罗马数字,应自动更新十进制数
if (!case1.getRomanNumeral().equals("XVI")) { // 字符串比较使用equals
working = false;
System.err.println("ERROR: Roman numeral was not set properly. It is " + case1.getRomanNumeral()
+ ". It should be XVI");
}
if (case1.getDecimalNumeral() != 16) { // 验证自动更新的十进制数
working = false;
System.err.println("ERROR: Decimal number was not updated properly by setRomanNumeral. It is " + case1.getDecimalNumeral()
+ ". It should be 16");
}
case1.setDecimalNumeral(2004); // 设置十进制数,应自动更新罗马数字
if (case1.getDecimalNumeral() != 2004) {
working = false;
System.err.println("ERROR: Decimal number was not set properly. It is " + case1.getDecimalNumeral()
+ ". It should be 2004");
}
if (!case1.getRomanNumeral().equals("MMIIII")) { // 验证自动更新的罗马数字 (2004 = MMIIII)
working = false;
System.err.println("ERROR: Roman numeral was not updated properly by setDecimalNumeral. It is " + case1.getRomanNumeral()
+ ". It should be MMIIII");
}
// 测试整数构造函数
RomanNumeral case2 = new RomanNumeral(1000);
String s = "M";
if(!(case2.getRomanNumeral().equals(s))) {
working = false;
System.err.println("ERROR: Decimal number constructor failed to set Roman numeral. It is " + case2.getRomanNumeral()
+ ", it should be M.");
}
if (case2.getDecimalNumeral() != 1000) {
working = false;
System.err.println("ERROR: Decimal number constructor failed to set Decimal numeral. It is " + case2.getDecimalNumeral()
+ ". It should be 1000");
}
// 测试字符串构造函数
RomanNumeral case3 = new RomanNumeral("M");
if(case3.getDecimalNumeral() != 1000) {
working = false;
System.err.println("ERROR: Roman numeral constructor failed to set Decimal numeral. It is " + case3.getDecimalNumeral()
+ ". It should be 1000");
}
if (!case3.getRomanNumeral().equals("M")) {
working = false;
System.err.println("ERROR: Roman numeral constructor failed to set Roman numeral. It is " + case3.getRomanNumeral()
+ ". It should be M");
}
// 测试一个包含多个字符的罗马数字转换
RomanNumeral case4 = new RomanNumeral("MDCLXVI"); // 1000+500+100+50+10+5+1 = 1666
if (case4.getDecimalNumeral() != 1666) {
working = false;
System.err.println("ERROR: Complex Roman numeral conversion failed. Expected 1666, got " + case4.getDecimalNumeral());
}
if (!case4.getRomanNumeral().equals("MDCLXVI")) {
working = false;
System.err.println("ERROR: Complex Roman numeral string mismatch. Expected MDCLXVI, got " + case4.getRomanNumeral());
}
if(working) {
System.out.print("Congratz! The test case works!");
} else {
System.out.print("Some tests failed. Please check the errors above.");
}
}
}注意事项:
本教程成功地在不使用Java内置数组或Map结构的情况下,实现了罗马数字与整数的相互转换。然而,这种实现方式有其局限性:
总结: 通过本教程,我们学习了如何在资源受限(不允许使用数组和Map)的环境下,以面向对象的方式实现罗马数字转换。关键的学习点包括:
尽管存在上述局限性,本实现为初学者提供了一个扎实的起点,有助于理解基本的编程逻辑、字符串处理和面向对象设计原则。在允许使用更高级数据结构时,可以进一步优化这些转换方法,以提高代码的简洁性和效率。
以上就是Java罗马数字转换教程:无需数组和Map实现整数与罗马数字互转的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号