英文:
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(", ");
ArrayList<String> dependenciesWOVersion = new ArrayList<String>();
String currentDependency;
for (String dependencyWithVersion : dependenciesWithVersion) {
ArrayList<String> currentRevDependencies = new ArrayList<String>(); // <- 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]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论