当前位置: 首页 > 面试题库 >

ConcurrentHashMap使使用JDK 8编译但针对JRE 7的应用程序崩溃

赵钊
2023-03-14
问题内容

今天,我遇到了一个非常意外的错误,尽管我能够找到一种方法来解决整个问题,但我不确定我是否完全理解它为什么做了它。

我正在使用的代码最初是使用针对JRE 7的JDK
7环境编写的。在代码中,我使用,ConcurrentHashMap并且需要遍历映射中的键。为此,我使用了map.keySet()根据JavaDocs应该返回的Set<K>。在我们的构建环境切换到JDK8之前,此方法运行良好。

当我们转移到JDK8时,我确保在调用javac时正在为1.7调用目标/源。因此,当代码想要遍历映射键时恰巧开始失败时,我感到非常惊讶。没有引发错误,没有异常,线程只是停止了。之后做一些研究,我发现Java8的实施ConcurrentHashMap.keySet()方法返回一个KeySetView<K,V>

我通过使用开关解决了这一问题map.keySet(),以得到一个Enumeration<K>使用map.keys()

现在,我对问题的猜测是,尽管自从使用JDK8以来,该项目是针对Java7进行编译的,但其中包含Java8库,但是为什么当它遇到不匹配时却没有引发错误或异常?

如下面的代码片段所示:

class MapProcessing
{
     private ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<String, Object>();

     public MapProcessing()
     {
           map.put("First",new Object());
           map.put("Second",new Object());
           map.put("Third",new Object());
     }


     public void processing()
     {
          // when calling this type of loop causes a freeze on our system.
          for(String key : map.keySet())
          {
              System.out.println(key);
          }
      }

     public void working()
     {
         // This is what I had to do to fix the problem.
         Enumeration<String> keys = map.keys();
         while(keys.hasMoreElements())
         {
              String key = keys.nextElement();
              System.out.println(key);
         }
     }
}

我们正在使用Oracle JDK 8 build 40在Windows 2012服务器上的javac中使用目标1.7和源1.7进行编译。

该代码使用Windows 2012服务器上运行的Oracle JVM 7 build 25运行。


问题答案:

如果我使用Java 8和javac -source 1.7 -target 1.8编译您的代码,然后使用Java 7运行它,则会得到一个

线程“主”中的异常java.lang.NoSuchMethodError:
  java.util.concurrent.ConcurrentHashMap.keySet()Ljava / util / concurrent / ConcurrentHashMap $ KeySetView;
    在stackoverflowt.Test.processing(Test.java:20)
    在stackoverflowt.Test.main(Test.java:27)

这是因为字节码看起来像

公共无效处理();
    码:
       0:加载_0       
       1:getfield#4 //字段映射:Ljava / util / concurrent / ConcurrentHashMap;
       4:invokevirtual#10 //方法java / util / concurrent / ConcurrentHashMap.keySet :()Ljava / util / concurrent / ConcurrentHashMap $ KeySetView;
       7:invokevirtual#11 //方法java / util / concurrent / ConcurrentHashMap $ KeySetView.iterator :()Ljava / util / Iterator;
      10:astore_1

并显式引用Java 7中不存在的ConcurrentHashMap $ KeySetView。我在Mac上使用Java 1.7.0_79和1.8.0_45

如果将代码更改为(仅使用地图界面):

private Map<String, Object> map = new ConcurrentHashMap<String, Object>();

那对我有用。字节码看起来像

公共无效处理();
    码:
       0:加载_0       
       1:getfield#4 //字段映射:Ljava / util / Map;
       4:invokeinterface#10,1 // InterfaceMethod java / util / Map.keySet :()Ljava / util / Set;
       9:invokeinterface#11,1 // InterfaceMethod java / util / Set.iterator :()Ljava / util / Iterator;
      14:astore_1


 类似资料:
  • 问题内容: 我的应用程序中的函数出现崩溃(来自Crashlytics,无法在本地重现): 由于我自己无法重现此错误,并且无法使用CoordinatorLayouts进行6个活动,因此如何进行调试? 编辑 :看起来它将在下一个支持库版本中修复 问题答案: 我遇到了类似的问题,因此降级到较旧的Android支持库版本(v24.1.1)对我来说很有用。库中似乎有问题,您可以在此处查看 Android I

  • 问题内容: 我已经使用构建了一个简单的可执行程序。 我已经将代码编译成静态二进制程序。 我想反编译输出二进制文件并获取Go源代码。 这有可能吗? 问题答案: 没有工具可以执行此操作,并且由于Go程序已编译为机器代码,因此它们所包含的信息不足,无法将其转换回Go代码。但是,仍然可以使用标准拆卸​​技术。

  • 这就是它崩溃的地方 01-12 13:44:12.571 296 26-29688/ca.dti.grounded.app E/OtherService:AsynchChecker 287:73 java.lang.IllegalStateException:Parcel已完成!在android.os.binderproxy.transactNative(本机方法)在android.os.bind

  • 我正在尝试将图像添加到我新创建的应用程序中。但是,当我运行我的应用程序时,它会崩溃。我没有在我的应用程序中编写任何代码,因此我提供了XML代码和错误日志。我在以前的应用程序中使用了ImageViews。没有错误。我已经优化了我的图像,但它仍然给我错误。 图像详细信息 错误日志: 09-08 16:03:02.266 15137-15137/ooper.loopE/AndroidRuntime: F

  • 当我运行应用程序并转到用户的活动时,应用程序崩溃,显示mUsersList。setHasFixedSize(真);正在使应用程序崩溃。 这是消息“由以下原因引起:java.lang.NullPointerException:尝试在空对象引用上调用虚拟方法'void androidx.recyclerview.widget.recyclerview.setHasFixedSize(布尔)'”

  • 问题内容: 我正在尝试按照本教程创建可执行文件 https://github.com/anthony- tuininga/cx_Freeze/tree/master/cx_Freeze/samples/Tkinter 进行一些调整后,我可以编译项目,但是当我单击.exe时,会触发加载鼠标的动画,但没有任何加载。之前曾问过这个问题,但从未解决过。 我的应用程式档案 我的setup.py 另外我一直在