java.lang.VerifyError - 具有包含对类实例的引用的静态变量的类

时间:2014-01-27 14:59:46

标签: java jvm

public class Config {
    public static Ref<Config> s = new Ref<Config>(new Config());
    static class Ref<T> {
        public T r;
        public Ref(T r) {
            this.r = r;
        }
    }
    public int INTERVAL = 4000;

    public Config()
    {
    }

    public static void main(String[] args) {
        System.err.println(Config.s.r.INTERVAL);
    }
}

将此原因运行到java.lang.VerifyError

Exception in thread "main" java.lang.VerifyError: (class: Config, method: main signature: ([Ljava/lang/String;)V) Incompatible type for getting or setting field

如果我这样做:

System.err.println(Config.s.r);

抛出没有异常,在调试中我可以看到'Config.s.r.INTERVAL'的值

当我使用-verbose:class运行时,我可以看到第一个示例中没有加载Ref类。在第二个例子中,加载了Ref类。

这是使用java6编译和运行的项目中唯一的类。 问题不在于jvm或第三方。

我猜这个问题是在同一行静态变量初始化和实例变量中组合。

像这样跑 - 工作:

Config c = Config.s.r;
System.err.println(c.INTERVAL);

聚苯乙烯。代码非常复杂,在dev env中分为2个类。我只是将它限制为简短的例子

Jdk - Java SE 6 [1.6.0_65-b14-462] 操作系统 - Mac

2 个答案:

答案 0 :(得分:1)

我想这是一个错误。 任何解决方法是拆分为2行,如下所示:

Config c = Config.s.r;
System.err.println(c.INTERVAL);

程序集之间的差异(差异仅在主函数中): 工作的,打破2行:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #22; //Field s:LRef;
   3:   getfield    #33; //Field Ref.r:Ljava/lang/Object;
   6:   checkcast   #1; //class Config
   9:   astore_1
   10:  getstatic   #37; //Field java/lang/System.err:Ljava/io/PrintStream;
   13:  aload_1
   14:  getfield    #27; //Field INTERVAL:I
   17:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   20:  return

}

破碎的一个 - 全部在一行:

public static void main(java.lang.String[]);
  Code:
   0:   getstatic   #33; //Field java/lang/System.err:Ljava/io/PrintStream;
   3:   getstatic   #22; //Field s:LRef;
   6:   getfield    #39; //Field Ref.r:Ljava/lang/Object;
   9:   getfield    #27; //Field INTERVAL:I
   12:  checkcast   #1; //class Config
   15:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   18:  return

}

在@Hot Licks身份的帮助下,问题是在破解版本的checkcast中检查字段(int)而不是类。打开Oracle的bug。

答案 1 :(得分:0)

翻译:

public static void main(java.lang.String[]);
  Code:
   // Fetch static field s -- place is stack location 1
   0:   getstatic   #22; //Field s:LRef;
   // Fetch instance field r using stack 1 as base -- place in stack location 1
   3:   getfield    #33; //Field Ref.r:Ljava/lang/Object;
   // Peform checkcast on stack location 1 to assure it's a "Config" -- leave stack unchanged
   6:   checkcast   #1; //class Config
   // Store stack location 1 into local variable 1.  Pop stack.
   9:   astore_1
   // Fetch static field System.err -- place in stack location 1
   10:  getstatic   #37; //Field java/lang/System.err:Ljava/io/PrintStream;
   // Fetch local variable 1 -- place in stack location 2
   13:  aload_1
   // Fetch instance field I using stack 2 as base -- place in stack location 2 
   14:  getfield    #27; //Field INTERVAL:I
   // Invoke println, using stack 1 as base, stack 2 as parm -- stack becomes empty
   17:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   20:  return

}

破碎的人:

public static void main(java.lang.String[]);
  Code:
   // Fetch static field System.err -- place is stack location 1
   0:   getstatic   #33; //Field java/lang/System.err:Ljava/io/PrintStream;
   // Fetch static field s -- place in stack location 2
   3:   getstatic   #22; //Field s:LRef;
   // Fetch instance field r using location 2 as base -- place in stack location 2
   6:   getfield    #39; //Field Ref.r:Ljava/lang/Object;
   // --- Note that the checkcast should be here ---
   // Fetch instance field I using location 2 as base -- place in stack location 2
   9:   getfield    #27; //Field INTERVAL:I
   // Perform checkcast on location 2, to assure it's a "Config" (it isn't)
   12:  checkcast   #1; //class Config
   // Invoke println using location 1 as base, location 2 as parm.
   15:  invokevirtual   #43; //Method java/io/PrintStream.println:(I)V
   18:  return

}