【发布时间】:2011-09-19 12:58:01
【问题描述】:
我一直在阅读代码和文档,试图了解类重载在 clojure 中的工作原理。根据许多网站,例如http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html,无论何时加载一个类,本质上都是获取字节码(通过任何数据机制),将字节码转换为类的实例(通过defineClass),然后解析(链接)该类通过解析类。 (defineClass 是否隐式调用 resolveClass?)。任何给定的类加载器只允许链接一个类一次。如果它试图链接一个现有的类,它什么也不做。这会产生一个问题,因为您无法链接新实例化的类,因此每次重新加载类时都必须创建类加载器的新实例。
回到 clojure,我尝试检查加载类的路径。
在 clojure 中,您可以根据需要以多种方式定义新类:
匿名类: 物化 代理
命名类: 定义类型 defrecord(在后台使用 deftype) 创类
最终,这些代码指向 clojure/src/jvm/clojure/lang/DynamicClassLoader.java
其中 DynamicClassLoader/defineClass 使用 super 的 defineClass 创建一个实例,然后缓存该实例。当你想检索类时,clojure 调用 forName 来调用类加载器和 DynamicClassLoader/findClass,它首先在缓存中查找,然后再委托给超类(这与大多数普通类加载器的工作方式相反,它们在首先委托,而不是自己尝试。)混淆的重点如下:forName 被记录为在类返回之前链接类,但这意味着您不能从现有的 DynamicClassLoader 重新加载类,而是需要创建一个新的 DynamicClassLoader,但是我在代码中没有看到这一点。 我知道代理和 reify 定义了匿名类,因此它们的名称不同,因此可以将其视为不同的类。但是,对于命名的类,这会发生故障。在实际的 clojure 代码中,您可以同时引用旧版本的类和引用新版本的类,但尝试创建新的类实例将是新版本的。
请解释 clojure 如何能够在不创建 DynamicClassLoader 的新实例的情况下重新加载类,如果我能理解重新加载类的机制,我想将此重新加载功能扩展到我可能使用 javac 创建的 java .class 文件。
注意事项: 这个问题是指类 RELOADING,而不是简单的动态加载。重新加载意味着我已经实习了一个类,但想实习该实例的新更新版本。
我想重申,目前尚不清楚 clojure 如何能够重新加载 deftype 定义的类。调用 deftype 最终会导致调用 clojure.lang.DynamicClassLoader/defineClass。再次执行此操作会导致再次调用 defineClass,但手动执行此操作会导致链接错误。下面发生了什么让 clojure 可以使用 deftypes 来做到这一点?
【问题讨论】:
标签: clojure classloader