Java非法类修饰符异常代码0x209

aur*_*amo 3 java eclipse

我有遗留代码库的问题.我想开始用1.6类格式编译它,但有一个问题只有在我尝试运行编译代码时才会显示出来.我得到以下异常:

java.lang.ClassFormatError:类FooBar 0x209中的非法类修饰符

谷歌搜索这并没有透露很多细节.据此,问题可能与接口和实现修饰符之间的不匹配有关.当然,它必须是一些新的限制,而不是1.5.

问题是类很大,并且有很多内部类和内部内部类,所以问题很难追查(这是我确定的内部类之一).毋庸置疑,该课程没有任何测试,因此改变它需要极其谨慎并且很费力.

那么,有没有人有关于0x209的任何确切信息 - 代码具体是什么意思?

编辑:

感谢Arne让我们朝着正确的方向前进,我们能够追踪问题并制定解决方法.根本原因尚不清楚,但现在我们可以避免它.

我们在某些领域使用Doug Lea的古老util.concurrent包,因为有些组件在只提供Java 1.1的环境中运行(是的,笑,我不介意).

这个相同的代码(使用并发工具)也被用作另一个相关软件的一个小组件.由于Doug的代码使用了1.2的一些特性,我们还被迫修改util.concurrent的某些部分,使其与Sun的1.1反向移植集合包兼容(无法找到那些链接).不知何故,它导致了这种特殊的Eclipse编译行为,当我们将类格式更改为Java 1.6时会发生这种行为.这是导致问题的最小代码:

EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import com.sun.java.util.collections.Map;

public class FooBar
{
    public static void main(String[] args) {
        Map.Entry e = (Map.Entry)(new ConcurrentHashMap().entrySet().iterator().next());
    }
}
Run Code Online (Sandbox Code Playgroud)

用Eclipse编译它(编译设置为1.6,1.5工作正常)并尝试从Sun的1.6 JRE加载类时出现问题.解决方法:我们循环访问键并使用键获取循环内部的值,而不是循环访问条目.

我们在这里的设置非常具有异国情调,难怪其他人都没有碰到这个.我终于检查了我们的构建脚本,并且看,ant-script有1.6个源和目标设置.显然这是特定于Eclipse的.

EDIT2:

我看得更接近我在这里链接的Sun bug报告.那里的问题也与com.sun.java.util.collections.Map.Entry有关.这与Sun的Javac有关.有趣.

Arn*_*sch 8

代码不是代码,而是类修饰符的内部表示形式,在类文件的字节代码中.

可以设置八个不同的标志.

ACC_PUBLIC (0x0001)
ACC_FINAL (0x0010)
ACC_SUPER (0x0020)
ACC_INTERFACE (0x0200)
ACC_ABSTRACT (0x0400)
ACC_SYNTHETIC (0x1000)
ACC_ANNOTATION (0x2000)
ACC_ENUM (0x4000)
Run Code Online (Sandbox Code Playgroud)

例如,公共final类将具有修饰符字节0x0011,即公共抽象类0x0401.

你的情况0x209(或更好:0x0209)是一个非法的修改器.它看起来像一个接口(0x0200),但0x0009部分不是规范的一部分.我猜这是一个编译器错误.

也许以下代码有助于隔离问题.它从类文件中读取类修饰符,并验证修饰符是否正常.如果不是它打印文件名和无效!也许您可以在类文件上使用此工具来隔离导致错误的类.

import java.io.*;

public class Main {

 public static void main(String[] args) throws Exception {
  String path = "D:/Arne/workspaces/IDEDeluxe/TestBytecode/bin/";
  String[] fileNames = { "Main.class" };
  for(String fileName : fileNames)
   traceFile(path, fileName);
 }

 private static void traceFile(String path, String fileName) throws FileNotFoundException, IOException {
  DataInputStream stream = new DataInputStream(new BufferedInputStream(new FileInputStream(path + fileName)));
  trace(fileName, readClassAccessFlags(stream));
  stream.close();
 }

 private static int readClassAccessFlags(DataInputStream stream) throws IOException {
  skipHeader(stream);
  skipConstantPool(stream);
  return stream.readUnsignedShort();
 }

 private static void skipHeader(DataInputStream stream) throws IOException {
  stream.readInt();
  stream.readUnsignedShort();
  stream.readUnsignedShort();
 }

 private static void skipConstantPool(DataInputStream stream) throws IOException {
  int constantPoolCount = stream.readUnsignedShort();
  for(int n = 1; n < constantPoolCount; n++) {
   int tag = stream.readUnsignedByte();
   switch(tag) {
   case 7:
    stream.readUnsignedShort();
    break;
   case 9:
   case 10:
   case 11:
    stream.readUnsignedShort();
    stream.readUnsignedShort();
    break;
   case 8:
    stream.readUnsignedShort();
    break;
   case 3:
   case 4:
    stream.readInt();
    break;
   case 5:
   case 6:
    stream.readInt();
    stream.readInt();
    break;
   case 12:
    stream.readUnsignedShort();
    stream.readUnsignedShort();
    break;
   case 1:
    stream.readUTF();
    break;
   }
  }
 }

 private static void trace(String fileName, int flags) {
  System.out.print(fileName + ": " + Integer.toHexString(flags) + " - ");
  if((flags & 0x0001) != 0)
   flags -= 0x0001;
  if((flags & 0x0010) != 0)
   flags -= 0x0010;
  if((flags & 0x0020) != 0)
   flags -= 0x0020;
  if((flags & 0x0200) != 0)
   flags -= 0x0200;
  if((flags & 0x0400) != 0)
   flags -= 0x0400;
  if((flags & 0x1000) != 0)
   flags -= 0x1000;
  if((flags & 0x2000) != 0)
   flags -= 0x2000;
  if((flags & 0x4000) != 0)
   flags -= 0x4000;
  if(flags == 0)
   System.out.println("OK!");
  else
   System.out.println("INVALID!!!");
 }

}
Run Code Online (Sandbox Code Playgroud)