按照 类加载过程 中的说明,验证是 链接 的第一部。

它主要包括以下几个方面的校验:

  1. 格式校验(Format Verification):JVM会检查类文件的二进制格式是否符合Java虚拟机规范。这包括检查魔数(Magic Number)是否正确、版本号是否支持当前JVM、常量池中的各种数据类型是否有效等。
  2. 语义校验(Semantic Verification):JVM会对类文件的字节码进行语义验证,以确保字节码的合法性和安全性。这包括验证字节码中的指令是否合法、操作数是否正确、访问权限是否满足等。例如,JVM会检查方法调用是否符合方法的签名、字段访问是否合法等。
  3. 字节码校验(Bytecode Verification):JVM会对字节码进行流程分析,以验证类文件的字节码逻辑是否正确。它会检查字节码中的跳转指令是否有效、循环是否正确等。这个过程可以防止字节码中的潜在问题,如死循环、无法到达的代码等。
  4. 符号引用校验(Symbolic Reference Verification):JVM会检查类文件中的符号引用是否有效。符号引用包括类、方法和字段的引用。JVM会验证这些引用是否可以正确解析,并检查访问权限是否满足。

通过这些校验步骤,JVM可以确保类文件的合法性和安全性。如果类文件未通过任何校验步骤,JVM将抛出VerifyError或相关的异常,阻止类文件的加载和执行,从而保证了Java程序的稳定性和安全性。

问题 1:implements 和 验证

因为代码里面有混淆,所以某些类的方法会被混淆掉。如果实现了某些接口,理论上是不能被混淆的。
如果混淆掉,就会导致 interfaceA#A -> classA#A 变成 interfaceA#A -> classA#B

所以如果 A 方法变成 B 方法,那么类验证过程中会失败么?

以下为例

提供接口 TestInterface

public interface TestInterface
{
    void test();
}

提供类 TestClass

public class TestClass implements TestInterface
{
    public void test1() {
        System.out.println("test");
    }
    
    public static void main(final String[] args) {
        final TestClass testClass = new TestClass();
        testClass.test1();
    }
}

然后调用,输出日志为

test

那么是否证明该方案没有问题呢?
并不是,当你调用 test() 方法的时候,就会抛出 AbstractMethodError()