Java HashMap处理包反向依赖时存储值与读取结果不一致问题
修复HashMap存储反向依赖的异常问题
我看了你的代码和运行结果,问题出在复用同一个ArrayList对象导致的引用混乱,这是Java里引用类型常见的坑。
问题根源分析
- 你在处理依赖的
for循环外面创建了currentRevDependencies这个ArrayList,所有依赖的反向依赖处理都共用这个对象的引用。 - 每次循环里的
currentRevDependencies.clear()会直接清空这个对象的内容——如果这个对象已经被存入revDependencies的多个键下,这些键对应的列表都会被同步清空。 - 比如你处理完
acl的libacl1依赖后,这个对象被存入revDependencies的libacl1键;之后处理acpi-support的acpid依赖时,你先clear了这个对象,再把它存入acpid键,这就导致libacl1对应的列表也被清空了。 - 还有个小细节:
currentDependency.trim()没有赋值给变量,String是不可变类型,这个调用不会改变原字符串,等于无效操作。
解决方案
每次处理单个依赖时,要么从revDependencies获取已有的反向依赖列表,要么新建一个全新的ArrayList,不要复用外部的对象。修改后的核心代码片段如下:
// 移除循环外的currentRevDependencies定义 String currentDependency; for (String dependencyWithVersion : dependenciesWithVersion) { int index = dependencyWithVersion.indexOf("("); // 修复trim()的赋值问题:String不可变,必须接收返回值 if (index != -1) { currentDependency = dependencyWithVersion.substring(0, index).trim(); } else { currentDependency = dependencyWithVersion.trim(); } dependenciesWOVersion.add(currentDependency); // 正确获取或新建反向依赖列表,避免复用同一对象 ArrayList<String> currentRevDependencies = revDependencies.get(currentDependency); if (currentRevDependencies == null) { currentRevDependencies = new ArrayList<>(); } currentRevDependencies.add(packageName); revDependencies.put(currentDependency, currentRevDependencies); System.out.print("Package: " + packageName + " Dependency: " + currentDependency + " RevDepencencies: " + revDependencies.get(currentDependency) + "\n"); }
完整修复后代码
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) { 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>(); String currentDependency; for (String dependencyWithVersion : dependenciesWithVersion) { int index = dependencyWithVersion.indexOf("("); // 修复trim()的赋值问题 if (index != -1) { currentDependency = dependencyWithVersion.substring(0, index).trim(); } else { currentDependency = dependencyWithVersion.trim(); } dependenciesWOVersion.add(currentDependency); // 正确获取或新建反向依赖列表 ArrayList<String> currentRevDependencies = revDependencies.get(currentDependency); if (currentRevDependencies == null) { currentRevDependencies = new ArrayList<>(); } 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"); } } }
修复后效果
修改后,每个反向依赖列表都是独立的对象,不会出现修改一个列表影响其他键的情况。最后遍历revDependencies时,每个键对应的列表都会和你即时打印的结果一致,比如libacl1会显示[acl],dbus显示[accountsservice],libc6显示[accountsservice, acl],完全符合预期。
内容的提问来源于stack exchange,提问作者Bautista Cardenau
相关产品推荐
相关产品推荐

