Java 是否有任何方式可以多次执行静态块?如果是的话,那怎么办?

Java 是否有任何方式可以多次执行静态块?如果是的话,那怎么办?,java,classloader,Java,Classloader,我的理解 静态块在类加载期间执行,如果类已加载,则除了类重新加载之外,没有其他方法加载该类 疑问/问题 1) 是否有JVM重新加载类的时间 我的理解 类内加载JVM加载Java文件的字节码,因此它无法将所有数千个类的字节码保存在内存中,因此它可能会丢弃很少使用的代码,并在必要时重新加载,在重新加载过程中JVM不会再次初始化静态变量和块(可能使用某种跟踪机制) 疑问/问题 2) 如果我的上述理解不正确,请纠正我的错误。Java语言规范详细介绍了类的加载、卸载和重新加载机制 加载是指查找具有特定名称

我的理解 静态块在类加载期间执行,如果类已加载,则除了类重新加载之外,没有其他方法加载该类

疑问/问题 1) 是否有JVM重新加载类的时间

我的理解 类内加载JVM加载Java文件的字节码,因此它无法将所有数千个类的字节码保存在内存中,因此它可能会丢弃很少使用的代码,并在必要时重新加载,在重新加载过程中JVM不会再次初始化静态变量和块(可能使用某种跟踪机制)

疑问/问题

2) 如果我的上述理解不正确,请纠正我的错误。

Java语言规范详细介绍了类的加载、卸载和重新加载机制

加载是指查找具有特定名称的
接口
类型的二进制形式的过程,可能是通过动态计算,但更典型的是通过检索编译器以前从源代码计算的二进制表示,并从该二进制形式构造,表示类或接口的
Class
对象

Java虚拟机规范的第5章给出了加载的精确语义(每当我们在本书中提到Java虚拟机规范时,我们指的是JSR 924修订的第二版)。这里,我们从Java编程语言的角度对该过程进行了概述

类或接口的二进制格式通常是上述Java虚拟机规范中所述的类文件格式,但也可以使用其他格式,只要它们满足§13.1中规定的要求。
class ClassLoader
defineClass
方法可用于从类文件格式的二进制表示中构造
class
对象

在某些情况下,可以卸载类和接口,这可能会导致无法预防的重新加载

Java编程语言的实现可以卸载类。如§12.6所述,当且仅当垃圾收集器可以回收类或接口的定义类加载器时,才可以卸载该类或接口。引导加载程序加载的类和接口可能无法卸载

类卸载是一种有助于减少内存使用的优化显然,程序的语义不应取决于系统是否以及如何选择实现优化,如类卸载。否则将损害程序的可移植性。因此,类或接口是否已卸载对于程序来说应该是透明的

但是,如果类或接口C在其定义加载程序可能可访问时被卸载,则C可能会被重新加载。人们永远无法确保这不会发生

事实上,它是为了解决您的具体问题:

例如,如果类具有以下情况,则重新加载可能不透明:

  • 静态变量(其状态将丢失)
  • 静态初始值设定项(可能有副作用)。
  • 本机方法(可能保持静态)
此外,类对象的哈希值取决于其标识。因此,通常不可能以完全透明的方式重新加载类或接口

由于我们无法保证卸载一个类或接口(其加载程序可能是可访问的)不会导致重新加载,并且重新加载从来都不是透明的,但卸载必须是透明的,因此,当一个类或接口的加载程序可能是可访问的时,不能卸载该类或接口。类似的推理可以用来推断引导加载程序加载的类和接口永远无法卸载

还必须说明,如果可以回收C类的定义类装入器,那么卸载C类是安全的。如果可以回收定义加载程序,那么就永远不会有对它的任何活动引用(这包括非活动的引用,但可能会被终结器重新激活)。反过来,只有当从实例或代码中永远不存在对该加载程序定义的任何类(包括C)的实时引用时,这才是真的

类卸载是一种优化,它只对加载大量类并在一段时间后停止使用其中大多数类的应用程序有意义。这种应用程序的一个主要示例是web浏览器,但还有其他一些。此类应用程序的一个特点是,它们通过显式使用类装入器来管理类。因此,上述政策对他们很有效

严格来说,本规范不必讨论类卸载问题,因为类卸载只是一种优化。然而,这个问题是非常微妙的,所以这里通过澄清的方式提到它


据我所知,JVM永远不会重新加载类本身;一旦类被加载,它将永远保持加载状态。因此,类定义保存在“PermGen”内存池中


但是,您的类的字节码有可能由多个类加载器加载,每次发生这种情况时,静态块都会再次执行,因为这是一个新类。每个类仅在其自己的类加载器的作用域内可见,而通常任何类加载器都可以看到位于类路径上的字节码,因此这是一种可能的情况(如果不需要的话)。

I如果显式使用新的类加载器再次加载该类,将再次执行此类的静态块。

如果加载类的
类加载器无法访问,则可以卸载类:

当且仅当类或接口的定义类加载器可由
 // 1st Static block invoked first.
static{
    System.out.println("hello...1");
}

// 2nd Static block, invoked after 1st static block above.
static{
    System.out.println("hello...2");
}


public static void Staticmeth() {
     System.out.println("hello...3");
}

public static void main(String ag[]){

}