Java.Lang.VerifyError: 피연산자 스택의 잘못된 유형
이 기사에서는 Java의 java.lang.VerifyError
에 대해 알아봅니다.
Java에서 java.lang.VerifyError
이해
java.lang.VerifyError
는 바이트코드 검증 과정에서 JVM(Java Virtual Machine)
에서 발생하는 오류입니다. 이 오류는 JVM이 클래스 또는 메소드의 바이트 코드가 유효하지 않거나 특정 제약 조건을 위반함을 감지할 때 발생합니다.
java.lang.VerifyError
가 발생할 수 있는 몇 가지 이유가 있습니다.
- 호환되지 않는 클래스 버전: 클래스를 실행하려는 JVM 버전과 다른 버전의 Java 컴파일러로 클래스를 컴파일하는 경우
VerifyError
가 발생할 수 있습니다. 이는 클래스가 최신 버전의 Java로 빌드되었지만 이전 JVM에서 실행되는 경우에 발생할 수 있습니다. - 호환되지 않는 라이브러리 버전: 클래스가 컴파일된 버전과 다른 버전의 라이브러리에 의존하는 경우
VerifyError
가 발생할 수 있습니다. - opcode의 불법 사용: 클래스 또는 메서드가 불법적이거나 지원되지 않는 방식으로 opcode를 사용하는 경우
VerifyError
가 발생할 수 있습니다. - 잘못된 클래스 파일 형식: 클래스 파일이 손상되었거나 형식이 잘못된 경우
VerifyError
가 발생할 수 있습니다. final
키워드의 잘못된 사용:final
변수가 초기화된 후 새 값이 할당되면VerifyError
가 발생할 수 있습니다.- 다른
classloader
가 클래스를 로드할 때 리플렉션을 사용하여 클래스의 전용 필드/메소드에 대한 액세스 가능성을 변경합니다.
이 오류를 수정하려면 문제의 원인을 찾아 수정해야 합니다. 여기에는 호환 가능한 버전의 Java 컴파일러로 클래스를 다시 컴파일하거나, 라이브러리 버전을 업데이트하거나, opcode의 불법 사용을 제거하는 작업이 포함될 수 있습니다.
리플렉션 사용으로 인한 오류인 경우 다른 클래스 로더
에 의해 로드된 클래스의 개인 필드/메소드에 대한 액세스 가능성을 변경하지 않음으로써 오류를 피할 수 있습니다.
일반적으로 사용 중인 Java 컴파일러 및 라이브러리의 버전을 알고 있고 호환성을 보장하기 위해 다른 버전의 JVM으로 코드를 테스트하는 것이 좋습니다. 또한 java.lang.VerifyError
와 같은 오류를 방지하려면 클래스 파일과 라이브러리를 최신 상태로 양호한 상태로 유지하는 것이 중요합니다.
java.lang.VerifyError
는 런타임 오류이며 컴파일 시간 오류인 java.lang.VerificationError
와 다릅니다.
Java에서 java.lang.VerifyError
의 예
더 잘 이해하기 위해 예를 살펴보겠습니다.
예제 1: A.java
및 B.java
라는 두 개의 Java 파일을 만듭니다.
A.java
파일:
public class A {
public A() {
System.out.println("Instance of A is created");
}
}
B.java
파일:
public class B extends A {
public B() {
super();
System.out.println("Instance of B is created");
}
public static void main(String[] args) {
B obj = new B();
}
}
이제 파일을 컴파일합니다.
javac A.java
javac B.java
두 파일 모두 오류 없이 제대로 컴파일됩니다.
그러나 class A
의 정의를 final
로 변경한 다음 class A
만 다시 컴파일한 다음 class B
의 main
메서드를 실행하면 다음 오류가 발생합니다.
Exception in thread "main" java.lang.VerifyError: Cannot inherit from final class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
......
......
이 오류는 클래스 A
의 정의를 변경했는데 클래스 B
가 클래스 A
의 이전 버전으로 실행되었기 때문에 발생합니다.
예 2:
세 개의 Java 파일 A.java
, B.java
및 C.java
를 만듭니다. class B
는 class A
를 상속하고 class C
에는 main
메서드가 포함됩니다.
A.java
파일:
public class A {
public A() {
System.out.println("Class A instance is created");
}
public void print() {
System.out.println("A::print()");
}
}
B.java
파일:
public class B extends A {
public B() {
super();
System.out.println("Class B instance is created");
}
public void print() {
System.out.println("B::print()");
}
}
‘C.java’ 파일:
public class C {
public static void _print_(A obj) {
obj.print();
}
public static void main(String[] args) {
B b = new B();
C._print_(b);
}
}
Java 파일을 별도로 컴파일한 다음 C.java
를 실행합니다.
javac A.java
javac B.java
javac C.java
java C
실행 결과는 다음과 같습니다.
Class A instance is created
Class B instance is created
B::print()
이제 class A
를 확장하지 않도록 class B
의 정의를 변경한 다음 B.java
를 다시 컴파일한 다음 class C
를 실행하면 다음 오류가 발생합니다.
Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
....
....
여기서도 클래스 B
의 정의를 변경했기 때문에 오류가 발생하지만 클래스 C
는 클래스 B
의 이전 버전으로 실행됩니다.