java 有没有什么方法可以让static block被执行多次?如果是,如何进行?

ldxq2e6h  于 2023-04-28  发布在  Java
关注(0)|答案(6)|浏览(191)

我的Understanding Static块在类加载期间执行,如果类已经加载,则除了类重新加载之外没有其他方法来加载类
疑问/问题1)JVM是否有时间重新加载类?
JVM加载Java文件的字节码,所以它不能在内存中保留所有数千个类的字节码,所以它可能会丢弃很少使用的代码,并在必要时重新加载它,并且在重新加载期间JVM不会再次初始化静态变量和块(可能使用某些跟踪机制)
疑问/问题
2)如果我以上的理解是不正确的那么请纠正我

czq61nw1

czq61nw11#

据我所知,JVM本身永远不会 * 重载 * 一个类;一旦类被加载,它就永远保持加载状态。由于这个原因,类定义被保存在“PermGen”内存池中。
然而,类的字节码可能被多个类加载器加载,每次发生这种情况时,静态块将再次被执行,因为这是一个新类。每个类只在它自己的类加载器的作用域中可见,而通常任何类加载器都可以看到你的字节码,如果它在类路径上,所以这是一种可能的(如果不希望的话)情况。

des4xlb0

des4xlb02#

如果加载类的ClassLoader变得不可访问,则可以卸载类: www.example.com
当且仅当类或接口的定义类加载器可以被垃圾收集器回收时,类或接口可以被卸载,如§12中所讨论的。6.
然后,如果类需要再次使用,它显然将再次加载。事实上,几个类加载器可以并行地分别加载同一个类。

fhg3lkii

fhg3lkii3#

当类被加载时,每个类加载器只执行一次静态块。静态块执行的顺序根据其发生,请参阅下面的示例代码及其输出。静态代码位于类级别,而不是每个示例化该类的ClassLoader的示例级别。注意:为了简洁起见,我没有在这里调用方法及其输出。
public class Testing {

// 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[]){

}

}
程序输出:-
你好..1
你好..2

6jygbczu

6jygbczu4#

如果你显式地使用一个新的ClassLoader来再次加载这个类,这个类的静态块将被再次执行。

wqnecbli

wqnecbli5#

Java语言规范非常详细地谈到了类的加载、卸载和重新加载机制。

JLS 12.2类和接口的加载

  • Loading* 指的是找到具有特定名称的classinterface类型的 binary 形式的过程,可能是通过动态计算,但更典型的是通过检索编译器先前从源代码计算的二进制表示,并从该二进制形式构造一个Class对象来表示类或接口。

加载的精确语义在Java虚拟机规范的第5章中给出(每当我们在本书中提到Java虚拟机规范时,我们指的是JSR 924修订的第二版)。在这里,我们提出了一个概述的过程中,从Java编程语言的观点。
类或接口的二进制格式通常是上面引用的Java虚拟机规范中描述的类文件格式,但其他格式也是可能的,只要它们满足§13中指定的要求。1. class ClassLoader的方法defineClass可以用于从类文件格式的二进制表示构造Class对象。
在某些情况下,可能会卸载类和接口,这可能会导致无法防止的重新加载。

12.7类和接口的卸载

Java编程语言的实现可以卸载类。当且仅当类或接口的定义类加载器可以被垃圾收集器回收时,类或接口可以被卸载,如§12中所讨论的。6.由引导加载器加载的类和接口可能无法卸载。
类卸载是一种有助于减少内存使用的优化。**显然,程序的语义不应该依赖于系统是否以及如何选择实现优化,例如类卸载。**否则会损害程序的可移植性。因此,类或接口是否已卸载对程序来说应该是透明的。
但是,如果类或接口C在其定义加载器可能可访问时被卸载,则C可能会被重新加载。谁也不能保证这种情况不会发生。
事实上,它解决了你的具体问题:
例如,如果类具有:

  • 静态变量(其状态将丢失)。
    *静态初始化器(可能有副作用)。
  • 本机方法(可以保持静态)。

此外,Class对象的哈希值取决于其标识。因此,一般来说,不可能以完全透明的方式重新加载类或接口。
由于我们永远不能保证卸载一个类或接口的加载器是潜在可达的不会导致重新加载,并且重新加载从来都不是透明的,但卸载必须是透明的,因此当它的加载器是潜在可达的时,不能卸载类或接口。可以使用类似的推理来推断由引导加载器加载的类和接口永远不能被卸载。
人们还必须讨论为什么卸载类C是安全的,如果它的定义类加载器可以回收。如果定义加载器可以被回收,那么就永远不会有任何对它的活动引用(这包括那些不是活动的,但可能被终结器复活的引用)。反过来,这只能是真的,如果永远不能有任何活引用的任何类定义的加载器,包括C,无论是从他们的示例或从代码。
类卸载是一种优化,它只对加载大量类并在一段时间后停止使用其中大部分类的应用程序有意义。这种应用程序的一个主要示例是Web浏览器,但还有其他应用程序。这类应用程序的一个特点是它们通过显式使用类加载器来管理类。因此,上述政策对他们很有效。
严格地说,本规范不一定要讨论类卸载的问题,因为类卸载只是一种优化。然而,这个问题非常微妙,因此在此提及以作澄清。

3zwtqj6y

3zwtqj6y6#

Andrzej Doyle回答了您的具体问题。然而:
在类加载期间执行MyUnderstandingStatic块
需要明确的是,loadinginitialization 是不同的阶段;可以在不初始化的情况下加载类。Java虚拟机规范指定了三个会导致类被初始化的条件:创建示例、调用静态方法、或者使用或分配非常量静态字段。

相关问题