Java:同一个类的项目中的两个罐子。

时间:2013-10-12 22:02:03

标签: java eclipse class jar import

我有一个java项目,它使用两个具有相同类(com.sun.mail.imap.IMAPFolder)的导入jar。有没有办法明确说明在导入类时使用哪个jar?使用:

import com.sun.mail.imap.IMAPFolder; 

似乎按照构建路径顺序使用该类,但由于某些原因导致

似乎不是这种情况
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: java.lang.NoSuchMethodError: com.sun.mail.imap.IMAPFolder.idle()V
        at com.woodbury.GCM.HelperGmailMonitor.doEmail(HelperGmailMonitor.java:104)
        at com.woodbury.GCM.Launch.listen(Launch.java:16)
        at com.woodbury.GCM.Launch.main(Launch.java:10)
        ... 5 more

在运行时。我正在eclipse中构建项目。

5 个答案:

答案 0 :(得分:17)

加载类时,匹配相关ClassLoader可见的请求的完全限定名称的第一个实现是返回的内容。具有相同完全限定名称的任何其他实现都有效地隐藏到ClassLoader

在标准Java SE应用程序中,这意味着在类路径中列出的第一个代码库(即jar)提供了它,并且隐藏了同一个完全限定类的所有其他代码库的实现

实施例

假设A.jar包含已编译的类

package com.stackoverflow.example;
public class Hello {
     public static String getGreeting(){
         return "Hello, A!"
     }
}

假设B.jar包含已编译的类

package com.stackoverflow.example
public class Hello {
     public static String getGreeting(){
         return "Hello, B!"
     }
}

请注意,上述两个类都具有相同的完全限定名称。

假设主要课程是

   import com.stackoverflow.example.Hello;

   public class ExampleMain {
       public static void main(String[] args){
            System.out.println(Hello.getGreeting());
       }
   }

如果我用

调用我的程序

java -cp A.jar:B.jar ExampleMain

输出为:Hello, A!

如果我像这样反转类路径

java -cp B.jar:A.jar ExampleMain

输出为:Hello, B!

答案 1 :(得分:9)

您无法在Java源代码中执行您所要求的操作。 Java不是为此而设计的。

这是一个糟糕的情况,只能通过自定义类加载器可靠地处理,每个加载器都提供您需要的其中一个罐子。既然你首先要问这个问题,这可能不是你应该去的方式,因为这会带来很多新的耗时问题。

我强烈建议您找出为什么您在类路径中有两个不同版本的同一个jar并重新编写程序,因此您只需要一个版本。

答案 2 :(得分:0)

1)通常:是的,您可以在不同的.jar文件中使用相同的类:您只需使用完全限定的包名称消除它们的歧义。 “Date”类(存在于java.util和java.sql中)就是一个很好的例子。

2)如果您有两个不同 .jar文件,这些文件具有 SAME 完全限定的软件包名称...可能性,您就会发生冲突。即使您可以通过使用类加载器来破解InvocationTargetException,您仍可能遇到其他问题。在这种情况下,听起来好像你的两个.jar文件有两个不同的JavaMail API实现。我不知道。

3)最安全的选择是满足您所有程序的参考没有冒着冲突的风险。我相信如果您从Oracle的JavaMail网页上获取“官方”.jar,您可以这样做:

https://java.net/projects/javamail/pages/Home

'希望有所帮助!

答案 3 :(得分:0)

是的,有办法解决这个问题。在我的场景中,我有两个具有相同名称和相同路径的类,eclipse总是导入错误的类。我所做的是更改构建路径中的jar顺序,eclipse将选择构建路径中的第一个。

答案 4 :(得分:0)

如果您使用的是IDE,则可以设置将文件导出到类加载器的顺序。

我在eclipse上工作,我使用maven。当我使用maven安装项目时,它产生了许多额外的jar(我没有在我的依赖项中定义)并且有一个文件org.w3c.dom.Element存在于2个jar文件中,同一个文件的第3个实例也存在于JRE7中

为了确保获取正确的文件,我所要做的就是转到 Java Build Path - > 订单和导出。选择Jar文件,我希望类加载器提供更多的首选项,并使用按钮" Up"来移动它。

这就是它的样子。 Eclipse - Java Build Path -> Order and Export 请注意,此图片适用于日食。但对于其他IDE,肯定会有类似的方法来解决这个问题。