classnotfoundexception即使我不使用那个类

fruv7luv  于 2021-06-29  发布在  Java
关注(0)|答案(2)|浏览(420)

我调用了下一个类的方法m1,但在我的类路径中没有类pkcsexception,我应该不需要它:

package otropack;

import iaik.pkcs.PKCSException;
import iaik.security.provider.IAIK;

public class Test {

    public static void m1(){
        System.out.println("Method 1");
    }

    public static void m2() {
        try {
            IAIK.addAsProvider(false);
            System.out.println("Method 2"); 
            throw new PKCSException();
        }catch(PKCSException e) {
            e.printStackTrace();
        }
    }
}

为什么调用test.m1()时会获得classnotfountexception?我调用了一个不使用该类的方法

Caused by: java.lang.ClassNotFoundException: iaik.pkcs.PKCSException

如果我用exception替换pkcsexception,它工作得很好,不会因为类路径中没有类iaik而给我一个错误。我也没有课。
非常感谢你!

eqzww0vc

eqzww0vc1#

当类加载器加载测试类时,它将尝试查找所有依赖类的定义。在您的代码中,它将失败并出现classnotfoundexception,因为您缺少类。

m3eecexj

m3eecexj2#

这是一个非常有趣的问题。答案就是验证者。
我们来做实验吧!

class Test {
    public static void main(String[] args) {
        m1();
    }

    public static void m1() { System.out.println("M1"); }

    public static void neverCalled() throws Exception {
        Exception e = new Ex1();
        // throw e; [1]
        // w1(e); [2]
        // w2(e); [3]
        // w3(e); [3]
    }

    private static void w1(Object x) {}
    private static void w2(Exception x) {}
    private static void w3(Serializable x) {}
}

class Ex1 implements Exception extends Exception {}

然后在命令行上:

> javac Test.java; rm Ex1.class; java Test

这很管用。
但是,如果取消注解[1],它就会失败。取消注解[2]就可以了。取消注解[3]并失败。取消注解[4]就可以了。
什么。这个。轻弹?
答案是,如果你做了几乎任何有趣的事情,它就会失败。特别是,“throw it”或“pass it as argument”计算在内,但如果参数类型为 j.l.Object 或任何接口。这很奇怪。变量的类型也无关紧要。写 Ex1 e = new Ex1(); 或者 Exception e = new Ex1(); 甚至 Object e = new Ex1(); ,这没什么区别。
另外,如果我们不删除ex1.class,而是在其中放置一个静态初始值设定项来打印'initialization!',它从不打印。这是jvm的保证。
那么,到底发生了什么?
是验证者。运行此 java -noverify Test 它将成功运行(打印 M1 )适用于所有情况;如果需要,请取消对所有4行的注解。
怎么回事?
验证器正在尝试验证由生成的堆栈帧 javac . javac或多或少地在生成的字节码中添加了一些注解,以使类验证器的工作更轻松(这是一种检查以编写的方式执行字节码是否可能导致核心转储或任何安全敏感的重要代码错误的方法)。验证这些注解是否正确,然后分析字节码是否存在堆损坏故障,要比推测没有注解就不存在堆损坏更容易。
然而,作为检查这些笔记的一部分,它需要知道 Ex1 如果ex1不存在,那么在生成任何堆栈帧注解的那一刻就会得到noclass错误,该注解告诉验证器堆栈中的某个地方将有一个ex1示例。因此,问题归结为:vm何时生成堆栈帧注解,这是一个奇怪的问题,但与上面的代码片段完全匹配: throw 作为非对象的一个参数,非接口调用确实如此。其他案子没有。
你可以从交易中得到一个实际的验证器错误。其实很简单:

> nano Test.java
class Test {
    public static void main(String[] args) {
        Ex1 e = new Ex1();
        m(e);
    }

    public static void m(Exception e) {}
}

> nano E1.java
class E1 extends Exception {}

> javac *.java
> nano E1.java
class E1 extends Thread {} // extend something else
> javac E1.java; # recompile _JUST_ E1
> java Test
VerifierError!

你能得出的一般结论很简单:
类中任何地方使用的任何类型都必须在运行时出现,否则只有在方法中使用的类型[a]从未被调用,并且[b]不会出现在任何堆栈帧注解中,这将避免出现错误,而这两种情况一起出现几乎从未发生过。但是,类初始化仅在代码实际运行时发生。因此,如果您想要编写代码的属性,如果从未实际执行过,则不会因为引用不存在的类而导致任何问题,您可以这样做,但前提是您将此代码隔离在其自己的类中:

package otropack;

import iaik.pkcs.PKCSException;
import iaik.security.provider.IAIK;

public class Test {

    public static void m1(){
        System.out.println("Method 1");
    }

    public static void m2() {
        Container.m2();
    }

    private static class Container {
      public static void m2() {
          try {
              IAIK.addAsProvider(false);
              System.out.println("Method 2"); 
              throw new PKCSException();
          }catch(PKCSException e) {
             e.printStackTrace();
          }
      }
    }
}

解决你的问题。根本没有类加载错误。

相关问题