为什么会出现ClassLoader异常,当存在两个具有类似类型名称的对象时?

3

我有一个含有2个方法的类。

  • method1() 中,我创建了一个名为 Abclocal record。这个 local record 只能在 method1() 中使用,因为它是在 method1() 中被定义的(根据 Java 的规则,在此处可以查看有关此规则的详细信息)。

  • method2() 中,我创建了一个名为 ABClocal interface。请注意,这里有一个大小写不同之处。前面提到的 local record 名称为 Abc,但是这个 local interface 名称为 ABC

以下是该类:

//package ..... //commenting out package information, as I sincerely doubt that is the cause

/** There seems to be a class loader error when running the below method in main(). */
public class ClassLoaderIssue
{

   /** Method 1. */
   private void method1()
   {
   
      record Abc(int a)
      {
      
         public static String iDontCare()
         {
         
            return "ignore this method";
         
         }
      
      }
      
      System.out.println(Abc.iDontCare()); //error
   
   }
   
   /** Method 2. */
   private void method2()
   {
   
      interface ABC
      {
      
      }
      
   }
   
 
   /**
    * 
    * Main method.
    * 
    * @param   args  commandline arguments that we don't care about for this example.
    * 
    */
   public static void main(String[] args)
   {
   
      new ClassLoaderIssue().method1();
   
   }
   
}

以下是我收到的异常信息。

Exception in thread "main" java.lang.NoClassDefFoundError: ClassLoaderIssue$1ABC (wrong name: ClassLoaderIssue$1Abc)
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at ClassLoaderIssue.method1(ClassLoaderIssue.java:23)
    at ClassLoaderIssue.main(ClassLoaderIssue.java:49)

以下是相关信息。

Java compile command = C:\Program Files\Java\jdk-17.0.2\bin\javac.exe
Java run command = C:\Program Files\Java\jdk-17.0.2\bin\java.exe

显然,这只是问题的一个可运行示例,但我遇到了一种情况,需要使用 本地类/枚举/记录 来处理域边缘的奇怪状态,这非常方便和有帮助。因此,我经常使用这个模式,但这是我第一次遇到这个问题。

现在显然,有很多方法可以解决这个问题。最简单的方法是我可以重新命名一个枚举值。我已经尝试过了,那样是行得通的。接口也是一样。

但为什么会发生这种情况呢?

编辑 - 我还测试了Java 18并得到了相同的结果。我使用了一个全新的文件夹和文件,并将文本(而不是文件)复制粘贴到同名的空文件中。仍然存在错误。我无法进行更干净的测试。

2个回答

5
在Windows系统中,文件名是不区分大小写的。这意味着命名为Something$ABC.class和Something$Abc.class的文件无法区分。
同时,编程语言本身是区分大小写的,并且要求文件名和文件内类的名称匹配。
你唯一的解决方法似乎是重命名类或接口。

非常好的发现,再次感谢。不过我有一个问题——这不应该被认为是一个我应该提交给Oracle的错误吗?我觉得这应该得到解决,因为它非常像是试图创建一个ABCAbc类文件。更重要的是,这会影响可移植性,而解决方案非常简单(只需将$1递增为$2)。 - davidalayachew
1
你可以尝试报告这个问题 - 我不确定他们会有多快响应。 - dangling else
我还应该补充一点 - 在进行这项工作时,我自己构建了JDK,但是所有预构建的测试版二进制文件都应该已经准备就绪。正如我所说,我在更新此内容时有些晚了。自那以后已经发布了几个测试版构建版本。 - davidalayachew
我忘记更新了,所以在这里 -- 由Archie Cobbs创建并在Java 21中发布了一个新的警告。如果你使用的是Java 21或更高版本,要么打开所有警告,要么打开this-escape警告。一旦你这样做了,我在帖子中描述的问题将会引发一个警告。 - undefined
以下是如何打开所有警告的方法 -- javac -Xlint:all Abc.java - undefined
显示剩余9条评论

0

我刚刚编译了代码并在我的电脑上运行了它。它没有任何问题。

也许尝试删除所有现有的类文件并重新编译所有内容。

否则,您可以尝试不同的Java版本,我过去也遇到过类似的问题。


我创建了一个全新的文件夹,将文本(而不是文件)复制到一个全新的文件中。编译并运行它,结果出现相同的错误。值得一提的是,我还在Java 18中进行了测试,并得到了相同的错误。 - davidalayachew
1
你正在使用Windows操作系统,文件名不区分大小写。我怀疑这可能是问题的原因。 - dangling else
@danglingelse 哇,太棒了。我试图在Windows中创建一个同名但大小写不同的文件,但它不让我这样做。我想这就是我的问题所在。 - davidalayachew
你在使用哪个命令来运行已编译的文件? - TwoOfTwelve
1
好的,我会把它写出来。 - dangling else
显示剩余2条评论

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