HashMap:添加新的可变值会将所有现有值更改为该值

时间:2017-04-21 20:46:45

标签: java hashmap

我只是制作一个简单的程序来计算班级成绩列表中的平均值。该程序从用户输入学生从课程中获得的分数,对其进行平均并将分数放在散列图上,其中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");

}

}

1 个答案:

答案 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;      
    }