我的理解静态块在类加载期间执行,如果一个类已经加载,那么除了类重载之外没有办法加载类
疑问/问题1)JVM有没有时间重新加载课程?
我在类加载中的理解JVM加载Java文件的字节码,因此它不能将所有数千个类字节码保存在内存中,因此它可能会丢弃很少使用的代码并在必要时重新加载它并且在重新加载期间JVM没有初始化静态变量和块再次(可能使用一些跟踪机制)
疑问/问题
2)如果我的上述理解不正确,请纠正我
据我所知,JVM 本身永远不会重新加载一个类; 一旦一个类被加载,它将永远保持加载状态.出于这个原因,类定义保存在"PermGen"内存池中.
但是,您的类的字节码可能由多个类加载器加载,每次发生这种情况时,静态块将再次执行,因为这是一个新类.每个类只在其自己的类加载器的范围内可见,而通常任何类加载器都可以看到你的字节码,如果它在类路径上,所以这是一种可能的(如果不希望的话)情况.
Java 语言规范详细讨论了类的加载、卸载和重新加载的机制。
\n\n\n加载是指查找具有特定名称的 a或类型的二进制形式的过程,可能是通过即时计算来实现的,但更常见的是通过检索编译器先前从源代码计算出的二进制表示形式,并从该二进制文件进行构造form,表示类或接口的对象。
\nclassinterfaceClass加载的精确语义在《Java 虚拟机规范》的第 5 章中给出(每当我们在本书中提到 Java 虚拟机规范时,我们指的是由 JSR 924 修订的第二版)。在这里,我们从 Java 编程语言的角度概述了该过程。
\n类或接口的二进制格式通常是上面引用的 Java 虚拟机规范中描述的类文件格式,但其他格式也是可能的,只要它们满足 \xc2\xa713.1 中指定的要求即可。
\ndefineClass的方法class ClassLoader可用于Class从类文件格式的二进制表示构造对象。
在某些情况下,可能会卸载类和接口,这可能会导致无法阻止的重新加载。
\n\n\nJava 编程语言的实现可以卸载类。当且仅当其定义的类加载器可以被垃圾收集器回收时,类或接口才可以被卸载,如 \xc2\xa712.6 中所述。引导加载程序加载的类和接口可能无法卸载。
\n类卸载是一种有助于减少内存使用的优化。显然,程序的语义不应该取决于系统是否以及如何选择实现类卸载等优化。否则就会损害程序的可移植性。因此,类或接口是否已被卸载对于程序来说应该是透明的。
\n但是,如果类或接口 C 在其定义加载器可能可达时被卸载,则 C 可能会被重新加载。人们永远无法确保这种情况不会发生。
\n
事实上,它解决了您的具体问题:
\n\n\n例如,如果类具有以下内容,则重新加载可能不透明:
\n\n
\n- 静态变量(其状态将丢失)。
\n- 静态初始化器(可能有副作用)。
\n- 本机方法(可能保留静态)。
\n此外,Class 对象的哈希值取决于其身份。因此,通常不可能以完全透明的方式重新加载类或接口。
\n由于我们永远无法保证卸载其加载器可能可达的类或接口不会导致重新加载,并且重新加载永远不是透明的,但卸载必须是透明的,因此,当类或接口的加载器可能可达时,不得卸载该类或接口。可以使用类似的推理来推断引导加载程序加载的类和接口永远无法卸载。
\n人们还必须争论,如果 C 类的定义类加载器可以被回收,为什么卸载 C 类是安全的。如果定义加载器可以被回收,那么永远不会有任何对它的实时引用(这包括非实时引用,但可能会被终结器复活)。反过来,只有当永远不能从实例或代码中对该加载程序定义的任何类(包括 C)进行任何实时引用时,这才是正确的。
\n类卸载是一种优化,仅对于加载大量类并且在一段时间后停止使用大部分类的应用程序才有意义。此类应用程序的一个主要示例是网络浏览器,但还有其他应用程序。此类应用程序的一个特点是它们通过显式使用类加载器来管理类。因此,上述政策对他们来说很有效。
\n严格来说,本规范并不一定要讨论类卸载问题,因为类卸载只是一种优化。不过,这个问题很微妙,所以在这里提一下,以供澄清。
\n