Java类型转换/类加载问题

3
以下是简化版问题:

这里是需要翻译的内容:

 SomeClass c = (SomeClass) obj.getSomeClassParent()

并不总是,但有时会触发异常。

 org.somepackage.SomeClass can't be cast to org.somepackage.SomeClass 

这怎么可能呢?我猜与JAI imageio是本地库有关,但是它是如何发生的呢?我可能漏了什么,但是什么呢?

I'm using JAI imageio version 1.1 
dcm4che 2.0.21  DICOM lib

这里是原始代码。
  ImageInputStream iis = ImageIO.createImageInputStream(src);
  Iterator<ImageReader> iter = ImageIO.getImageReadersByFormatName("DICOM");
  ImageReader reader = iter.next();
  DicomImageReadParam param = (DicomImageReadParam) reader.getDefaultReadParam();

以及原始异常

org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam can't be cast to    
org.dcm4che2.imageio.plugins.dcm.DicomImageReadParam

异常图片 http://img215.imageshack.us/img215/3894/exception.jpg


这是一个链接到异常图片的网址。

可能是重复的问题:https://dev59.com/1XRA5IYBdhLWcg3wyRF6 - Eran Medan
4个回答

8
我认为这可能发生在以下情况下:
  1. 从ClassLoader X加载了SomeClass实例(因此它的类是CL(X).SomeClass),
  2. 但是它正在不同的类加载器中进行转换。例如,当前线程的类加载器是Y,因此SomeClass实际上是CL(Y).SomeClass
因此,您有:
  • 实例类 = CL(X).SomeClass
  • 类转换目标 = CL(Y).SomeClass
换句话说 - 不是相同的类 - 因此会出现类转换异常。

可能是重复的问题:将对象强制转换为相同类时出现ClassCastException - 它也提供了一些好的建议。


2
你基本上已经掌握了这个问题。问题在于每个实例都由不同的类加载器加载,因此对这些实例中的每一个调用getClass()方法将返回相同类的不同实例。你应该稍微修改一下,因为一个类会被两个类加载器加载,而不是一个实例在一个类加载器中,另一个类在另一个类加载器中,这实际上是不可能的。 - Robin
确实,SomeClass在两个类加载器中都被加载了,但我的意思是将从在CL X中加载的类的实例转换为在CL Y中加载的类。我会编辑答案。 - Eran Medan
@Ehrann Mehdan - 非常清晰,但您应该删除有关序列化的部分,因为在这种情况下不适用。 - Robin
@Robin @ Ehrann,问题肯定出在类加载器上。但是为什么我在一个应用程序中有不同的类加载器仍然是个谜。我正在努力寻找一个好的解决方案。 - Mite Mitreski
可能与此无关,但值得一看:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24566 - Eran Medan

2
我猜您的问题可能是由于类加载器和本地库之间的不匹配引起的。本地库会被加载并与类加载器相关联,但程序只能真正加载一个本地库实例。因此,如果您在类加载器A中加载了本地库,并且它输出的类将与类加载器A关联。如果您稍后在类加载器B中加载相同的本地库,则您并没有真正再次加载它,它仍然会为类加载器A传递类。所以,要么您重新部署了Web应用程序,要么您在同一Web服务器上有2个使用相同本地库的Web应用程序。
如果可能,您应该尝试将本地库放在Web服务器的基本类路径中,这样它将由基本类加载器加载,从而可以被任何Web应用程序使用。如果您无法这样做,并且问题仅是重新部署问题,则您可能需要在重新部署之前卸载并等待一段时间(理论上,当与其关联的类加载器被GCed时,本地库将被卸载,但当然,这可能需要未知的时间)。

1

奇怪,你尝试将它强制转换为一个它继承的对象,不确定它是否具有你需要的功能,但试试看是否仍然会抛出异常。


1
从图片中我看到它看起来像一个Web应用程序。我读到了“catalina”。因此,很有可能是一个纯粹的类加载问题。
例如,如果您从ImageIO类获取的ImageReader是由不同的类加载器加载的(可能是因为它部署在不同的Web应用程序中),那么getDefaultReadParam()方法返回的DicomImageReadParam对象就是一个 - 从技术上讲 - 不同类的实例。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接