使用Java 8 update101 HashMap.entries时,无法将其强制转换为集合

使用Java 8 update101 HashMap.entries时,无法将其强制转换为集合,java,java-8,Java,Java 8,在更新到Java8Update101之后,我在下面的代码中遇到异常。它与Java8Update91配合得很好 访问密钥库: KeyStore ks = KeyStore.getInstance("WINDOWS-MY"); ks.load(null, null); Field field = ks.getClass().getDeclaredField("keyStoreSpi"); field.setAccessible(tr

在更新到Java8Update101之后,我在下面的代码中遇到异常。它与Java8Update91配合得很好

访问密钥库:

        KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
        ks.load(null, null);

        Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
        field.setAccessible(true);

        KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

        Collection entries;

        field = kss.getClass().getEnclosingClass().getDeclaredField("entries");
        field.setAccessible(true);

        // This is where the exception happens
        entries = (Collection) field.get(kss);

        // I then have to loop on these entries, something like this:

        for (Object entry : entries) { //code }
类型转换,引发异常:

java.util.HashMap cannot be cast to java.util.Collection

Java8Update101最近有什么变化吗?如何解决它?

我使用以下测试代码确认它不起作用

import java.util.HashMap;
import java.util.Collection;

public class HelloWorld {
   public static void main(String[] args) {
      HashMap map = new HashMap();
      Collection c;
      c = (Collection) map;
   }
}
结果是线程“main”java.lang.ClassCastException中出现异常:java.util.HashMap不能转换为java.util.Collection 位于HelloWorld.main(HelloWorld.java:8)

您可以像这样使用values()方法覆盖它

import java.util.HashMap;
import java.util.Collection;

public class HelloWorld {
   public static void main(String[] args) {
      HashMap map = new HashMap();
      Collection c;
      c = map.values();
   }
}
import java.util.HashMap;
import java.util.Collection;
import java.security.*;
import java.lang.reflect.Field;

public class HelloWorld {
   public static void main(String[] args) {
    try{
      KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
        ks.load(null, null);

        Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
        field.setAccessible(true);

        KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

        Collection entries;

        field =kss.getClass().getEnclosingClass().getDeclaredField("entries");
        field.setAccessible(true);
        entries = ((HashMap) field.get(kss)).values();
    }catch(Exception e){
        e.printStackTrace();
    }
   }
}
所以你的代码应该是这样的

import java.util.HashMap;
import java.util.Collection;

public class HelloWorld {
   public static void main(String[] args) {
      HashMap map = new HashMap();
      Collection c;
      c = map.values();
   }
}
import java.util.HashMap;
import java.util.Collection;
import java.security.*;
import java.lang.reflect.Field;

public class HelloWorld {
   public static void main(String[] args) {
    try{
      KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
        ks.load(null, null);

        Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
        field.setAccessible(true);

        KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

        Collection entries;

        field =kss.getClass().getEnclosingClass().getDeclaredField("entries");
        field.setAccessible(true);
        entries = ((HashMap) field.get(kss)).values();
    }catch(Exception e){
        e.printStackTrace();
    }
   }
}
如何解决

正如评论中所指出的,你所做的是令人讨厌的。您不应该混淆库类的内部实现细节。他们很容易改变,然后你的代码就会被破坏。。。正如它在这里所做的那样

最好的解决方案是限制自己对
KeyStore
使用公共API方法;例如,调用
alias()
,然后迭代生成的
枚举
查找每个别名的条目


如果您不能做到这一点,那么您需要修改代码以使用您和代码的其他用户可能遇到的所有不同的
KeyStore
实现。

以下更改将使其与8u101一起工作,但它并没有消除这样一个事实,即您正在弄乱类
密钥库的内部结构,而实际上您不应该弄乱这些内部结构

问题是,在Java 8u101中,某些对象从
集合
变成了
哈希映射
,而
哈希映射
不是
集合
,因此尝试将其强制转换为
集合
会导致
ClassCastException

KeyStore ks = KeyStore.getInstance("WINDOWS-MY");
ks.load(null, null);

Field field =  ks.getClass().getDeclaredField("keyStoreSpi");
field.setAccessible(true);

KeyStoreSpi kss = (KeyStoreSpi) field.get(ks);

Collection entries;

field =kss.getClass().getEnclosingClass().getDeclaredField("entries");
field.setAccessible(true);
entries = (HashMap)field.get(kss);

for (Map.Entry entry : entries) {
    Object key = entry.getKey();
    Object value = entry.getValue();
    System.out.println(key + " = " + value);
}

在Java8U101之前,您需要访问这个私有字段来解决这个bug。此错误已在Java 8u101中修复,因此您可以继续使用官方密钥库API。

您可以通过不处理其他类的私有数据成员来解决它。因为虽然
Map
是集合框架的一部分,但它不扩展
集合
,通过反射访问私有字段,您正在搞乱类
密钥库的内部结构。你不应该那样做,现在你正在承受后果。类的实现可能会在Java版本之间发生变化,这可能发生在8u91到8u101之间。仅使用诸如
KeyStore
之类的类,不要通过反射访问私有字段进行黑客攻击。你为什么需要这样做?@tarunk你在搞乱类的非公开实现细节。JDK开发人员可以自由地更改这些细节,因为他们没有承诺任何特定的行为。@tarunk最近的更改是什么意思<代码>地图
从未可铸造到
集合
。如果它比
集合
接口有例如
add(ee)
元素方法。在
Map
的键value的上下文中这意味着什么?它在Java8更新91中运行良好。你能确认一下吗?是的,我知道我也试过了。您需要使用values()方法我拥有的是Collection entries=(Collection)field.get(kss)。现在,集合条目=(集合)((field.get(kss)).values());beacues不起作用。get()返回类型Object,value()不能与之一起使用。@tarunk只是按原样粘贴了代码。我也测试了它。Cheers@tarunk你导入java.util.HashMap了吗现在我粘贴了从命令行编译和运行的文件当然,现在你有了8u101之前版本无法使用的代码…很有趣!你似乎是第一个真正试图理解海报在做什么以及为什么的人。您是否有任何关于问题中的代码是此错误的解决方法这一事实的来源的参考?在针对此错误的示例中,确实可以看到
JavaKeyStore
类的
entries
字段以某种方式更改了其类型,从而导致了原始帖子中描述的问题。