我只是制作一个简单的程序来计算班级成绩列表中的平均值。该程序从用户输入学生从课程中获得的分数,对其进行平均并将分数放在散列图上,其中Key表示课程名称,Value表示给定分数。但是,我遇到的问题是,每增加一个键,所有先前放置的值都会被新值替换。 我使用的HashMap是嵌套的:
Map<String, Map<String, Double>> courseList = new HashMap<>();
输入文件采用此格式
Biology Test 30 90 80 Quiz 20 50 80 90 Homework 50 5 10 20 30 40 50
Calc Test 50 100 80 Quiz 20 88 50 30 50 Homework 30 5 10 20 30
第一个单词是班级的名称。之后,列出每个作业收到的分数。每次分配后的第一个数字表示它们在平均计算中的重量。因此,对于第一行,列出了生物学的学生成绩。他们的测试重量为30%,在第一次测试中获得90分,在第二次测试中获得80%。测验重20%,而家庭作业占50%。所以对于第一行,程序输出
{Biology={Quiz=73.33333333333333, Test=85.0, Homework=25.833333333333332}}
这是正确的;但是,当程序完成第二行时,第二行的平均值将替换第一行。输出变为
{Biology={Quiz=54.5, Test=90.0, Homework=16.25}, Calc={Quiz=54.5, Test=90.0,
Homework=16.25}}
知道这是怎么发生的吗?当我试图调试时,似乎发生在嵌套的HashMap被放入外部的时候。我在想这可能是值共享一个可变变量,但我认为只有可变键是问题?如果是这种情况,最好的解决方法是什么?
参考代码:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class GpaCalculatorTest {
private static String courseName;
static Map<String, Map<String, Double>> courseList = new HashMap<>();
static void loadCourse(String courseGradeFile) {
String[] courseInfo = null;
try (BufferedReader br = new BufferedReader(new FileReader(
courseGradeFile))) {
String line;
while ((line = br.readLine()) != null) {
courseInfo = line.split("\\s+");
String course = courseInfo[0];
Grades.loadGrade(course, courseGradeFile);
courseList.put(course, Grades.gradeList);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(courseList);
}
private static final String[] ASSIGNMENTTYPE = { "Test", "Quiz",
"Homework", "Essay", "Final_Project", "Final_Essay" };
static class Grades {
static Map<String, Double> gradeList = new HashMap<>();
static void loadGrade(String course, String courseGradeFile) {
String[] courseInfo = null;
try (BufferedReader br = new BufferedReader(new FileReader(
courseGradeFile))) {
String line;
while ((line = br.readLine()) != null) {
courseInfo = line.split("\\s+");
if (courseInfo[0].equals(course)) {
break;
}
}
} catch (FileNotFoundException e) {
System.out.println("File was not found");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < courseInfo.length; i++) {
if (Arrays.asList(ASSIGNMENTTYPE).contains(courseInfo[i])) {
double sumOfGrade = 0;
int counter = 0;
for (int j = i + 2; j < courseInfo.length; j++) {
if (Arrays.asList(ASSIGNMENTTYPE).contains(
courseInfo[j])) {
break;
} else {
sumOfGrade += Integer.parseInt(courseInfo[j]);
counter++;
}
}
double average = sumOfGrade / counter;
gradeList.put(courseInfo[i], average);
}
}
}
}
public static void main(String[] args) {
loadCourse("C:\\Users\\john\\workspace\\ideas\\src\\"
+ "gpacalculator\\course_grades");
}
}
答案 0 :(得分:0)
正如评论所暗示的那样:问题来自静态领域。
事实上,据我所知,静态甚至不是真正的问题。
真正的问题是你使用一个字段作为全局变量来在类之间共享数据,而你不需要任何字段但只改变你的类的api。
当然,使用静态字段进行操作通常会产生更多的副作用和问题......
这里:
while ((line = br.readLine()) != null) {
courseInfo = line.split("\\s+");
String course = courseInfo[0];
Grades.loadGrade(course, courseGradeFile);
courseList.put(course, Grades.gradeList);
}
Grades.loadGrade(course, courseGradeFile);
不会返回任何内容。
相反,它会改变静态字段。为什么?
装载操作应该返回一些东西
只需这样做:返回Map
并将其存储在courseList
:
while ((line = br.readLine()) != null) {
courseInfo = line.split("\\s+");
String course = courseInfo[0];
Map<String, Double> gradesMap = Grades.loadGrade(course, courseGradeFile);
courseList.put(course, gradesMap);
}
以这种方式更改loadGrade()
:
static class Grades {
// remove it : static Map<String, Double> gradeList = new HashMap<>();
...
static Map<String, Double> loadGrade(String course, String courseGradeFile) {
Map<String, Double> gradeMap = new HashMap<>();
...
return gradeMap;
}