为什么 Java 中会出现 Java.lang.VerifyError 以及如何解决?

javaobject oriented programmingprogramming更新于 2024/11/3 22:04:17

Java.lang.VerifyError 是由 JVM(Java 虚拟机)引起的运行时错误。在运行时,会进行验证过程以检查已加载的 .class 文件的有效性,如果 .class 文件违反任何约束,则 JVM 将给出 Java.lang.VerifyError 错误。Java 1.0 版及更高版本中存在以下错误。

java.lang.LinkageError 扩展了 Java.lang.VerifyError,后者指的是程序的链接过程出现问题。

Java.lang.VerifyError 的输出结果如下:

线程"main"中的异常 java.lang.VerifyError:(类:com/example/Way2Class,方法:myMethod 签名:()V)与函数不兼容的参数
在 com.example.MyClass.main(MyClass.java:10)

此输出包含导致错误的类的名称 (Way2class)、类路径 (com/example/Way2Class)、错误行 (10)、方法名称 (myMethod) 和错误消息 (线程"main"中的异常 java.lang.VerifyError)

此错误可能由于以下各种原因而发生:

  • 版本不匹配:需要注意的是,如果使用Java 编译器的版本与用于执行代码的版本不同。

示例

public class VerifyErrorVersionExample {
   public static void main(String[] args) {
      System.out.println("Hello, program!");
   }
}

如果此特定程序使用 Java 9 编译并在 Java 8 等早期版本上运行,则输出将显示以下错误解释:

输出

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
   Location:
      VerifyErrorVersionExample.main([Ljava/lang/String;)V @2: invokestatic
   Reason:
      Type 'java/lang/invoke/StringConcatFactory' (current frame, stack[0]) is not assignable to 'java/lang/invoke/MethodHandle'
   Current Frame:
      bci: @2
      flags: { }
      locals: { '[Ljava/lang/String;' }
      stack: { 'java/lang/invoke/StringConcatFactory' }
   Bytecode:
      0x0000000:  getstatic    #2   // Field java/lang/System.out:Ljava/io/PrintStream;
      0x0000003:  ldc          #3   // String Hello, world!
      0x0000005:  invokestatic #4   // Method java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/MethodHandle;
      0x000000a:  ldc          #5   // String 
      0x000000c:  iconst_1
      0x000000d:  anewarray   #6   // class java/lang/Object
      0x0000010:  dup
      0x0000011:  iconst_0
      0x0000012:  ldc          #7   // String !!!
      0x0000014:  aastore
      0x0000015:  invokevirtual #8   // Method java/lang/invoke/MethodHandle.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;
      0x000001a:  checkcast   #9   // class java/lang/String
      0x000001d:  invokevirtual #10  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      0x0000020:  return  
  • 字节码损坏:如果对类文件的字节码进行更改或损坏,则可能会出现错误。

示例

public class VerifyErrorBytecodeExample {
   public static void main(String[] args) {
      int a = 10;
      int b = 20;
      int c = a + b;
      System.out.println("The sum of " + a + " and " + b + " is " + c);
   }
}

输出

Exception in thread "main" java.lang.VerifyError: (class: VerifyErrorBytecodeExample, method: main signature: ([Ljava/lang/String;)V) Illegal target of jump or branch
      at java.lang.Class.getDeclaredMethods0(Native Method)
      at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
      at java.lang.Class.getDeclaredMethod(Class.java:2128)
      at java.io.ObjectStreamClass.getPrivateMethod(ObjectStreamClass.java:1743)
      at java.io.ObjectStreamClass.access$1700(ObjectStreamClass.java:72)
      at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:513)
      at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:492)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:492)
      at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:389)
      at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1134)
      at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
      at VerifyErrorBytecodeExample.main(VerifyErrorBytecodeExample.java:6)
  • 类文件不一致:如果类文件违反了 Java 虚拟机规范所施加的某些限制。

示例

public class VerifyErrorExample {
   public static void main(String[] args) {
      Animal animal = new Cat();
      animal.speak();
   }
}
interface Animal {
   void speak();
}
class Dog implements Animal {
   public void speak() {
      System.out.println("Woof!");
   }
}
class Cat extends Dog {
   public void speak() {
      System.out.println("Meow!");
   }
}

此程序定义了一个"Animal"接口和两个实现该接口的具体类:Dog 和 Cat。Cat 扩展了 Dog 并覆盖了其说话方法。在主方法中,我们创建了一个 Cat 实例并调用了其说话方法。

假设我们选择从当前类路径中取出 Dog 类,然后继续重新编译和运行我们的程序,将显示 java.lang. VerifyError。此错误将显示如下错误消息:

输出

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
   Location:
      VerifyErrorExample.main([Ljava/lang/String;)V @2: invokevirtual
   Reason:
      Type 'Cat' (current frame, stack[0]) is not assignable to 'Dog'
   Current Frame:
      bci: @2
      flags: { }
      locals: { '[Ljava/lang/String;' }
      stack: { 'Cat' }
   Bytecode:
      0000000:  new           #2                  // class Cat
      0000003:  dup
      0000004:  invokespecial #3                  // Method Cat."":()V
      0000007:  astore_1
      0000008:  aload_1
      0000009:  invokevirtual #4                  // Method Animal.speak:()V
      000000c:  return

结论

总之,出现 java.lang.VerifyError 的原因可能多种多样,从字节码波动到安全计算实践中的限制,再到代码库中包含的所有不一致的相互依赖的 Java 组件版本,还有运行时的库兼容性问题等。避免此问题的一个非常重要的方法是确保所有正在使用的库在运行时都与您的系统和其他依赖库兼容。注意这些要求将确保遵守 Java 的字节码规定,从而避免出现有问题的编码实践,例如不遵守安全协议或提交类文件中存在不一致的代码,这些代码可能会导致后续错误。每当出现 java.lang.VerifyError 时,必须仔细检查相关的错误消息以及您可以获得的任何堆栈跟踪,以便确定确切的问题并采取必要的纠正措施。


相关文章


有用资源