我认为这是每个Java程序员遇到的情况,如果他们做得足够长的话.您正在进行一些调试并对课程进行更改.当你重新运行程序时,这些更改似乎没有被提取,而是旧的类似乎仍在运行.你清理和重建一切,同样的问题.有时,这可以归结为类路径问题,同一类在类路径上不止一次,但似乎没有一种简单的方法来确定加载的类来自哪里......
有没有办法找到已加载的类的文件路径?如果从.class文件或.jar文件加载类,则优先使用.有任何想法吗?
我最近读了很多关于Java类加载过程的内容.我经常遇到这样的文本,声称在运行时期间无法在类路径中添加类并在没有类加载器hackery(URLClassLoaders等)的情况下加载它们.
据我所知,类是动态加载的.这意味着它们的字节码表示仅在需要时加载并转换为java.lang.Class对象.
所以,在JVM启动后,不应该可以在类路径中添加JAR或*.class文件并加载这些类,只要它们尚未加载?(要清楚:在这种情况下,类路径只是文件系统上的文件夹."添加JAR或*.class文件"只是意味着将它们放在这个文件夹中.)
如果没有,这是否意味着在JVM启动时搜索类路径,并且找到的类的所有完全限定名称都缓存在内部"列表"中?
如果你能指出我的答案中的一些消息来源,你会很高兴.最好的SUN文档:Sun JVM Spec.我已阅读规范,但无法找到有关类路径的任何内容,以及它是否已在JVM启动时完成.
PS
这是一个理论问题.我只想知道是否有可能.我想实现没有任何实际意义.只有我对知识的渴望:)
我一直在阅读代码和文档,试图了解类重新加载在clojure中的工作原理.根据许多网站,如http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html,每当你加载一个类本质上你获得字节码(通过任何数据机制),转换将字节码转换为类Class的实例(通过defineClass),然后通过resolveClass解析(链接)该类.(defineClass是否隐式调用resolveClass?).任何给定的类加载器只允许链接一次类.如果它试图链接现有的类,它什么都不做.这会产生问题,因为您无法链接新实例化的类,因此每次重新加载类时都必须创建类加载器的新实例.
回到clojure,我尝试检查加载类的路径.
在clojure中,您可以根据需要以多种方式定义新类:
匿名类:reify代理
命名类:deftype defrecord(在引擎盖下使用deftype)gen-class
最终,这些代码指向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做到这一点?
我想在运行时替换一些方法的内容.
我知道我可以使用javassist但它不起作用,因为我想要增强的类已经被系统classLoader加载.
我该怎么做,在运行时替换方法的内容?我应该尝试卸载课程吗?我怎样才能做到这一点 ?我看到它是可能的,但我无法弄清楚如何做到这一点.
如果可能的话,我想避免使用外部库,我想自己编写代码.
更多信息: - 我想要增强的类包含在一个框架中(在一个jar文件中) - 我的代码实际上是这个框架的一个插件 - 我的插件运行的框架有自己的classLoader,但是这个classLoader没有加载自己的类(它将它们委托给系统类加载器) - 我正在使用的框架是Play.
谢谢您的帮助 !
如果我有一个内部类声明,例如:
Class A {
public static class B {
}
}
Run Code Online (Sandbox Code Playgroud)
其次是:
Class<?> implClass = getClass().getClassLoader().loadClass("A");
Run Code Online (Sandbox Code Playgroud)
A $ B内部类也会被加载吗?如果B内部类没有被声明为"静态"怎么办?
此评论是在代码审核中进行的,而制作该评论的人不再在我们的团队中.
在运行时必须由类加载器解析的任何类型都不应该具有被声明为final和static的引用保持的实例.
这是代码行:
private final static Logger log = LoggerFactory.getLogger(MyClass.class);
Run Code Online (Sandbox Code Playgroud)
我熟悉声明loggers静态或非静态的争论,但这个评论似乎更为通用.我找不到为什么静态和最终都不好的任何解释.有人可以详细说明吗?
在我们的应用程序中,我们有时会遇到以下异常:
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
- with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory]
Run Code Online (Sandbox Code Playgroud)
我们已经发现只有当我们使用时才会发生这种情况,Collection.parallelStream()但如果我们使用Collection.stream().
我们看到 JAXBThread.currentThread().getContextClassLoader()用于加载类。我们还看到,当使用 时parallelStream(),执行我们命令的线程使用不同的类加载器。有时是org.apache.catalina.loader.WebappClassLoader,有时是jdk.internal.loader.ClassLoaders.AppClassLoader。
现在看来,AppClassLoader不知道 JAXB 依赖项,而WebappClassLoader。
我们正在使用 Java 11 和以下 Maven 依赖项:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
知道有什么问题吗?怎么可能,AppClassLoader不知道我们的依赖关系?
Eclipse的logcat for Android中的这条消息是什么意思?
W/ActivityThread: ClassLoader.getResources: The class loader returned by Thread.getContextClassLoader() may fail for processes that host multiple applications. You should explicitly specify a context class loader. For example: Thread.setContextClassLoader(getClass().getClassLoader());
Run Code Online (Sandbox Code Playgroud)
不幸的是,没有关于此警告的上下文,所以我不知道是什么导致了这个问题以及我如何解决它.
我在示例应用程序中看到了使用商业JDBC驱动程序的这一行:
Class.forName("name.of.a.jcdb.driver")
Run Code Online (Sandbox Code Playgroud)
不使用返回值.
这条线的目的是什么?
我刚读完Java虚拟机规范,关于类加载的部分让我感到困惑.据我所知,在阅读规范之后,我认为类的整体实例化按以下顺序组成:
创建/加载:类加载器定位表示类的字节流,可以是文件或网络流,也可以是实现要获取的类加载器的任何类型.如果找不到类,ClassNotFoundException则抛出a.此时,ClassFormatError如果字节数组不表示Java类(例如,缺少幻数)或者UnsupportedClassVersionError正在运行的JVM实例不支持类版本,则已经发生了一些基本验证.
链接:该类被挂钩到JVM中.如果出现问题,LinkageError则抛出一个子类.链接由三个子步骤组成:
验证:确保字节流表示Java类,例如字节代码没有形式错误,例如溢出操作数堆栈的方法字节代码.如果一个类验证失败,VerifyError则抛出一个.
准备:JVM为所有静态字段分配内存,并可能创建实例模板以加速实例创建.创建虚拟方法表.在此阶段不会抛出类加载特定错误.(OutOfMemoryError虽然可能会抛出.)
解决方案:现在以运行时常量池的形式加载到方法区域中的所有符号引用都将解析为此JVM加载的实际类型.如果可以解析符号引用但导致定义冲突,IncompatibleClassChangeError则抛出a.如果找不到引用的类,NoClassDefFoundError则抛出a ClassNotFoundException,它基本上包装了类加载器尝试加载此引用类所引发的类.如果引用的类引用自身,ClassCircularityError则抛出a.解决方案可以以两种方式之一发生,这取决于JVM的实现者
渴望:现在解决对其他字段,方法或类的所有符号引用.
懒惰:将符号引用的解析推迟到第一次使用方法时.这可能会带来一个引用不存在的类的类永远不会抛出错误,如果这个引用永远不需要解决.
初始化:运行在类static中定义为Java代码的类的初始化程序.如果这样的初始化程序引起异常,则会重新包含此异常ExceptionInInitializerError.
令我困惑的是上述类加载机制的解析阶段.为什么分辨率被定义为链接中的明确步骤,具体在准备之后发生?已经在类加载阶段的描述中,提到了
如果C具有任何直接超接口,则使用§5.4.3.1的算法解析从C到其直接超接口的符号引用.
验证发生后,符号引用是否也未得到解决,因为描述了验证:
验证(第4.10节)确保类或接口的二进制表示在结构上是正确的(第4.9节).验证可能会导致加载其他类和接口(第5.3节),但不需要对它们进行验证或准备.
我总是记住这张照片

资料来源:http://www.programcreek.com
我几乎在任何解释课程加载的地方都看到过.如果分辨率不情愿被看作是所有阶段的一部分,全面负责创建/加载,验证, …