有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java可以加载系统类加载器。运行时指定的类文件?

我正在为作业编写一个静态分析工具,它使用ASM库分析Java字节码。我们使用的ASM的一个部分要求(或者至少看起来要求)从类加载器加载类

我们希望该工具能够进行分析。类文件,而不需要在类路径上使用它们。我们已经加载了。类,并使用InputStream将其读入。在大多数情况下,这对于ASM是可以接受的。有些类,例如SimpleVerifier,试图加载这些类

在这种情况下,是否可以注册。对要加载的文件进行分类,以便对Class.forName()的调用将加载它们?或者有没有一种简单的方法来扩展类加载器来实现这一点


编辑:关于URLClassLoader的信息很有用。不幸的是,在这种情况下,将Thread.currentThread().setContextClassLoader()用于该实例是行不通的。我调用的库代码使用一个加载程序,它在实例初始化时使用getClass().getClassLoader()检索该加载程序

当我设置URLClassLoader时,该类还没有初始化,所以我猜contextClassLoader没有加载该类

我是否正确理解了回答?是否可以使用URLClassLoader加载第三方类


共 (6) 个答案

  1. # 1 楼答案

    差不多

    如果在某个地方编译了类,可以使用URLClassLoader加载它们。然后可以将这个类加载器设置为当前线程的类加载器:Thread.setContextClassLoader(ClassLoader)

    用户可以获取当前线程上下文类加载器并使用该加载器访问类定义

  2. # 2 楼答案

    我创建了自己的类加载器,非常简单

     /**
     * Used to hold the bytecode for the class to be loaded.
     */
    private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();
    
    @Override
    protected Class<?> findClass(final String name) throws ClassNotFoundException {
        final byte[] bytes = BYTE_CODE.get();
        if (null == bytes) {
            throw new ClassNotFoundException(name);
        }
        return this.defineClass(null, bytes, 0, bytes.length);
    }
    
  3. # 3 楼答案

    据我所知,您不能在运行时扩展系统类加载器,但可以使用URLClassLoader从任意位置(jar或目录)动态加载类

  4. # 4 楼答案

    是的,您可以使用URLClassLoader

    我有一个在运行时加载类的测试。该类不在类路径中(甚至在运行测试时也不存在),稍后将加载并运行良好

    这是密码

    void testHello() throws MalformedURLException, ClassNotFoundException {
        URL[] url = {
                new URL("file:/home/oreyes/testwork/")
        };
    
        try {
            new URLClassLoader(url).loadClass("Hello");
            throw new AssertionError("Should've thrown ClassNotFoundException");
        } catch ( ClassNotFoundException cnfe ){}
    
    
        c.process();// create the .class file 
    
        new URLClassLoader(url).loadClass("Hello");
    
        // it works!!
    }
    

    摘自本question

  5. # 5 楼答案

    首先,ASM的使用方式可以避免使用ClassLoader获取类的信息

    ASM框架中有几个地方默认加载类,但所有这些地方都可以在您自己的子类中重写。在我的脑海里:

    • ClassWriter.getCommonSuperClass()方法仅在ClassWriter时调用。使用COMPUTE_FRAMES标志,可以覆盖该标志,使其不使用ClassLoader获取有关类的信息。您可以在ClassWriterComputeFramesTest中找到这样一个例子,它引入了ClassInfo抽象
    • 类似的简化器。getClass()方法由SimpleVerifier.isAssignableFrom()使用,您可以覆盖后者并使用ClassInfo抽象来查找公共超类型。若我并没有弄错的话,AspectWerkz项目在其类型模式匹配代码中实现了类似的功能。另外请注意,还有SimpleVerifier.setClassLoader()方法,如果您仍然希望加载自己的类,可以使用该方法

    另一方面,在Sun的JVM上,加载的类到达PermGen区域,无法卸载,因此,如果可以避免这种情况,则仅为静态代码分析目的加载类不是一个好主意,特别是如果该工具将集成到一个长期存在的进程(如IDE)中

  6. # 6 楼答案

    您可以尝试在应用程序启动时设置一个“启动器”,创建一个URLClassLoader,将类路径上的位置和您自己的.class位置传递给它,然后从该类加载器启动应用程序

    SimpleVerifierURLClassLoader加载时,它还能够从额外的位置加载类