2011-08-31 226 views
-1

每次创建包含这些变量的对象的新实例时,都会初始化静态变量吗?或者当对象首次被调用时,它们是否只初始化一次?静态变量初始化

+7

你是什么意思的“实例静态变量”?这就像谈论“String int变量”。 –

+2

有没有这样的事情作为实例静态变量。你有一个实例变量或静态(类)变量! –

+3

而且你不会调用一个对象 - 只有它的方法。 – DJClayworth

回答

11

你说

被初始化例如静态变量...

停在那儿,声明是没有意义的。静态变量存在于类中,而不是在任何特定的实例上。它们在初始化过程中初始化,该过程在创建实例,运行类的静态方法或访问类的静态变量时运行。 (完全披露,@布鲁诺的回答让我知道这些信息)。

+1

类加载!=类初始化。 –

+1

@bruno“编译器实际上做的是在内部产生一个类初始化例程,它按照它们出现在类声明中的顺序将所有静态变量初始化器和所有静态初始化器代码块组合在一起。只会在班级第一次加载时自动运行,一次。“从简单的Java – hvgotcodes

+1

hvgotcodes,不要相信书籍。 **这简直是错误的**。去检查虚拟机规格部分2.17.4和2.17.5(在我的答案下面的链接)。一个类在加载时不会被初始化。如果您使用多个类加载器,则可以多次加载一个类并进行多次初始化。 –

3

静态字段的类(的初始化期间初始化不混合初始化装载,他们是不同的东西 - 一个类可以加载,你可以做反射就可以了,没有永远不会初始化它)。

此外,如果您使用多个ClassLoader s,类初始化可能会多次发生给定的类。

见VM规格section 2.17.4, Initializationsection 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())); 
    } 
} 

(我希望当您指定的URLClass缺少URL[]对象这个编译装载机的构造......)

注意,有必要设定的类加载器的父母null,否则他们的父母将是主要的应用程序类加载器(即加载的类Main),则因为Java代表相同首先默认加载到父类加载器,如果类A在类路径中,则只会看到加载和初始化一次。

最后,请注意,Class.load("A")不等于classLoader.loadClass("A")。如果您检查文档Class.load(String),您会看到此方法加载初始化该类。有一个Class.load(...)超载,它需要一个布尔值来指示它是否应该初始化类。

+0

可以一个类多次初始化?第2.17.5节中的一行表示“如果类或接口已经被初始化,则不需要进一步的操作。释放对象的锁并正常完成。” – hvgotcodes

+1

是的。在运行时,一个类由元组(ClassLoader,Package,Name)标识。如果你使用2个不相关的类加载器,你将有2 *个不同的*类(具有相同的名称,以便它们各自的Class对象是!c1.equals(c2),但是c1.getName()。equals(c2)。 getName())是true),所以初始化过程可以每个发生一次。 –