每次创建包含这些变量的对象的新实例时,是否会初始化静态变量?或者在首次调用对象时它们只被初始化一次?
答案 0 :(得分:11)
你说
初始化实例静态变量 ...
在那里停下来,声明毫无意义。静态变量存在于类中,而不是任何特定实例上。它们在初始化过程中初始化,该过程在创建实例,运行类上的静态方法或访问类上的静态变量时运行。 (完全披露,@ Bruno的回答让我了解了这个信息)。
答案 1 :(得分:3)
静态字段在类的初始化期间初始化(不要混合初始化和加载,它们是不同的东西 - a class可以被加载,你可以对它进行反射,而无需初始化它。)
此外,如果您使用多个ClassLoader
s,则对于给定的类,类初始化可能会多次发生。
请参阅VM Spec section 2.17.4, Initialization和section 2.17.5, Detailed initialization procedure,详细了解何时加载一个类以及何时将其初始化。
编辑:一个简单的例子,它将显示如何加载一个类和多次初始化,并且加载不会自动暗示初始化:
public class A { static { System.out.println("I've been initialized!"); } }
public class Main {
public static void main(String... args) {
ClassLoader cl = new URLClassLoader(..., null);
System.out.println("loading...");
Class<?> aClass = cl.loadClass("A");
// here you could perform reflection on aClass, without initializing it
System.out.println("Will be initialized now:");
Object o = aClass.newInstance();
System.out.println("Let's load once again...");
ClassLoader cl2 = new URLClassLoader(..., null);
Class<?> aClass2 = cl2.loadClass("A");
System.out.println("Will be initialized a second time:");
Object o2 = aClass2.newInstance();
// the following is false:
System.out.println("aClass1.equals(aClass2) = " + aClass1.equals(aClass2));
// the following is true:
System.out.println("aClass1.getName().equals(aClass2.getName())" + aClass1.getName().equals(aClass2.getName()));
}
}
(我希望在URLClassLoader的构造函数中指定缺少的URL[]
对象时进行编译...)
请注意,有必要设置类加载器的父级null
,否则它们的父级将是主应用程序类加载器(即加载类Main
的相同),然后因为Java默认情况下首先将加载委托给父类加载器,如果类A
在类路径中,您只会看到加载和初始化一次。
最后,请注意Class.load("A")
不等同于classLoader.loadClass("A")
。如果您查看Class.load(String)
的文档,您会看到此方法加载并初始化该类。有Class.load(...)
的重载,它带有一个布尔值,表明它是否应该初始化类。