Java HashMap将值存储在意外的键中。

huangapple go评论79阅读模式
英文:

Java HashMap stores values in keys not intended

问题

我正在处理一个程序,用于提取有关软件包的信息。然而,我在处理反向依赖关系时遇到了一些问题(请查看注释下方的部分:检查先前的反向依赖关系并保存它们)。主要问题是,在将值放入哈希映射(HashMap)后,打印出来时,似乎以正确的方式存储了这些值。然而,在完成整个过程后,打印映射的键和值会返回其他值。代码之后可见打印出来的信息。

以下是代码:

public class MainActivity {
    public static void main(String[] args) {
        // ...(省略了代码开头部分)

        for (String key : revDependencies.keySet()) {
            System.out.print(key + " " + revDependencies.get(key) + "\n");
        }
    }
}

以下是屏幕上打印出的内容:

Package: accountsservice Dependency:  dbus RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libaccountsservice0  RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libc6  RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libglib2.0-0  RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libpolkit-gobject-1-0  RevDepencencies: [accountsservice]
Package: acl Dependency:  libacl1  RevDepencencies: [acl]
Package: acl Dependency: libc6  RevDepencencies: [accountsservice, acl]
Package: acpi-support Dependency:  acpid  RevDepencencies: [acpi-support]

acpid  [acpi-support]
libaccountsservice0  [accountsservice, acl]
libpolkit-gobject-1-0  [accountsservice, acl]
libglib2.0-0  [accountsservice, acl]
libc6  [accountsservice, acl]
dbus [accountsservice, acl]
libacl1  []

看起来存储的值与在处理过程完成后打印出的值不同。

英文:

I am working on a program that tells you information about a package. However, I am having some issues with reverse dependencies (see under comment: Check for previous reverse dependencies and save them). The main issues is that when printing, right after putting the values in the HashMap, it seems to be storing them in the correct way. Nevertheless, printing the key and values of the map after finishing the process returns other values. Printed information can be seen after code.

public class MainActivity {
    public static void main (String[] args) {
        ArrayList<String> packages = new ArrayList<String>();
        ArrayList<String> descriptions = new ArrayList<String>();
        HashMap<String, ArrayList<String>> dependencies = new HashMap<>();
        HashMap<String, ArrayList<String>> revDependencies = new HashMap<>();
        int i = 0;
        String packageStart = "Package:";
        String descriptionStart = "Description:";
        String dependenciesStart = "Depends:";

        String packageName = "";

        BufferedReader reader;
        try {
            reader = new BufferedReader(new FileReader(
                    "/var/lib/dpkg/status"));
            String line = reader.readLine();
            while (line != null) {
                //System.out.println(line);

                if (line.startsWith(packageStart)) {
                    packageName = line.substring(packageStart.length()).trim();
                    packages.add(packageName);
                }
                if (line.startsWith(descriptionStart)) {
                    descriptions.add(line.substring(descriptionStart.length()).trim());
                }
                if (line.startsWith(dependenciesStart)) {
                    String subline = line.substring(dependenciesStart.length());
                    String[] dependenciesWithVersion = subline.split(", ");
                    ArrayList<String> dependenciesWOVersion = new ArrayList<String>();
                    ArrayList<String> currentRevDependencies = new ArrayList<String>();
                    String currentDependency;

                    for (String dependencyWithVersion : dependenciesWithVersion) {
                        int index = dependencyWithVersion.indexOf("(");
                        currentRevDependencies.clear();

                        //Take the version out of the package name
                        if (index != -1) {
                            currentDependency = dependencyWithVersion.substring(0, index);
                        } else {
                            currentDependency = dependencyWithVersion;
                        }
                        currentDependency.trim();
                        dependenciesWOVersion.add(currentDependency);

                        
                        //Check for previous reverse dependencies and save them
                        if (revDependencies.get(currentDependency) != null){
                            currentRevDependencies = revDependencies.get(currentDependency);
                        }

                        currentRevDependencies.add(packageName);
                        revDependencies.put(currentDependency, currentRevDependencies);

                        System.out.print("Package: " + packageName + " Dependency: " + currentDependency + " RevDepencencies: " + revDependencies.get(currentDependency) +  "\n");
                    }
                    dependencies.put(packageName, dependenciesWOVersion);

                    if (i == 2){
                        break;
                    }
                    i++;
                }
                line = reader.readLine();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        for (String key : revDependencies.keySet()){
            System.out.print(key + " " + revDependencies.get(key) + "\n");
        }

   }
} 

The following is printed on the screen:

Package: accountsservice Dependency:  dbus RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libaccountsservice0  RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libc6  RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libglib2.0-0  RevDepencencies: [accountsservice]
Package: accountsservice Dependency: libpolkit-gobject-1-0  RevDepencencies: [accountsservice]
Package: acl Dependency:  libacl1  RevDepencencies: [acl]
Package: acl Dependency: libc6  RevDepencencies: [accountsservice, acl]
Package: acpi-support Dependency:  acpid  RevDepencencies: [acpi-support]

acpid  [acpi-support]
libaccountsservice0  [accountsservice, acl]
libpolkit-gobject-1-0  [accountsservice, acl]
libglib2.0-0  [accountsservice, acl]
libc6  [accountsservice, acl]
dbus [accountsservice, acl]
libacl1  []

The values that seem to be storing are not the ones printed when the process finishes.

答案1

得分: 2

问题

Java通过值传递对象引用。当您将List currentRevDependencies放入您的revDependencies Map中时,存储在Map中的不是List的副本,而只是对象引用。当currentRevDependencies在外部被改变时(比如您在其上调用clear),映射中的列表也会改变。这意味着在while循环的一次迭代中添加的所有键,List引用将是相同的,导致您观察到的重复值。

如何修复

要解决这个问题,对于放入Map中的每个键值对,请为其创建一个新的List,而不是每次都清除上一个Map,如下所示:

//[...]
String subline = line.substring(dependenciesStart.length());
String[] dependenciesWithVersion = subline.split(", ");
ArrayList<String> dependenciesWOVersion = new ArrayList<String>();
String currentDependency;

for (String dependencyWithVersion : dependenciesWithVersion) {
    ArrayList<String> currentRevDependencies = new ArrayList<String>(); // <- 每次迭代时实例化新列表

    //[...]

    revDependencies.put(currentDependency, currentRevDependencies);
}
dependencies.put(packageName, dependenciesWOVersion);
//[...]

输出:

包名:libasan0 依赖:gcc-4.8-base  逆依赖:[libasan0]
包名:libasan0 依赖:libc6  逆依赖:[libasan0]
包名:libasan0 依赖:libgcc1  逆依赖:[libasan0]
包名:libasan0 依赖:libstdc++6  逆依赖:[libasan0]
包名:libvorbisfile3 依赖:libc6  逆依赖:[libvorbisfile3]
包名:libvorbisfile3 依赖:libogg0  逆依赖:[libvorbisfile3]
包名:libvorbisfile3 依赖:libvorbis0a  逆依赖:[libvorbisfile3]
包名:libquadmath0 依赖:gcc-4.9-base  逆依赖:[libquadmath0]
包名:libquadmath0 依赖:libc6  逆依赖:[libasan0, libquadmath0]
 libc6  [libvorbisfile3]
libvorbis0a  [libvorbisfile3]
 gcc-4.9-base  [libquadmath0]
libgcc1  [libasan0]
libc6  [libasan0, libquadmath0]
libstdc++6  [libasan0]
 gcc-4.8-base  [libasan0]
libogg0  [libvorbisfile3]
英文:

The issue

Java passes passes object references by value. When you put the List currentRevDependencies into your revDependencies Map, what is being stored in the Map is not a copy of the List but merely an object reference. When currentRevDependencies is changed externally (like you calling clear on it), the list inside the map changes. That means for all keys added in one iteration of the while loop, the List reference will be the same, leading to the duplicate values you observe.

How to fix it

To fix this issue, create a new List for every key value pair you put into the Map instead of clearing the last Map each time like so:

//[...]
String subline = line.substring(dependenciesStart.length());
String[] dependenciesWithVersion = subline.split(&quot;, &quot;);
ArrayList&lt;String&gt; dependenciesWOVersion = new ArrayList&lt;String&gt;();
String currentDependency;

for (String dependencyWithVersion : dependenciesWithVersion) {
    ArrayList&lt;String&gt; currentRevDependencies = new ArrayList&lt;String&gt;(); // &lt;- instantiate new list each iteration

    //[...]

    revDependencies.put(currentDependency, currentRevDependencies);
}
dependencies.put(packageName, dependenciesWOVersion);
//[...]

Output:

Package: libasan0 Dependency:  gcc-4.8-base  RevDepencencies: [libasan0]
Package: libasan0 Dependency: libc6  RevDepencencies: [libasan0]
Package: libasan0 Dependency: libgcc1  RevDepencencies: [libasan0]
Package: libasan0 Dependency: libstdc++6  RevDepencencies: [libasan0]
Package: libvorbisfile3 Dependency:  libc6  RevDepencencies: [libvorbisfile3]
Package: libvorbisfile3 Dependency: libogg0  RevDepencencies: [libvorbisfile3]
Package: libvorbisfile3 Dependency: libvorbis0a  RevDepencencies: [libvorbisfile3]
Package: libquadmath0 Dependency:  gcc-4.9-base  RevDepencencies: [libquadmath0]
Package: libquadmath0 Dependency: libc6  RevDepencencies: [libasan0, libquadmath0]
 libc6  [libvorbisfile3]
libvorbis0a  [libvorbisfile3]
 gcc-4.9-base  [libquadmath0]
libgcc1  [libasan0]
libc6  [libasan0, libquadmath0]
libstdc++6  [libasan0]
 gcc-4.8-base  [libasan0]
libogg0  [libvorbisfile3]

huangapple
  • 本文由 发表于 2020年8月19日 16:33:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/63483054.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定