单例 - 早期初始化,静态字段初始化和类加载

时间:2012-07-13 16:54:34

标签: java

考虑这段代码:

class MyClass {
    private static MyClass myobj = new MyClass();

    private MyClass() {
    }

    public  static MyClass getMyobj() {
        return myobj;
    }
}

1)在上面的代码中,当myobj加载Myclass时加载getMyobj()或第一次调用MyClass.getMyobj(); MyClass.getMyobj(); MyClass.getMyobj(); 时会{}}

2)假设我们两次打电话:

MyClass()

它会在第二次调用时创建新的{{1}}对象吗?

6 个答案:

答案 0 :(得分:2)

  1. 何时加载您的课程

  2. 不,它不会创建另一个对象,它将使用已存在的对象

答案 1 :(得分:1)

  

1)在上面的代码中myobj何时会被初始化

首次加载课程时。

  

2)假设我们调用两次:...它会在第二次调用时创建新的MyClass()对象吗?

否,主要是因为myobj是静态的,所以getMyobj()将始终返回相同的实例,即在加载时创建的实例。

答案 2 :(得分:1)

  1. 当MyClass加载时。

  2. 即使你召唤十次,MyClass也只有一个实例。

答案 3 :(得分:1)

正如已经指出的那样,该对象将在初始化类时创建,并且因为该方法只是返回它,所以在示例代码中不会创建其他此类实例。

但是,如果您想要做这样的事情,您还可以使用单个实例创建enum

public enum MyClass {
   myobj;
}

然后,需要使用myobj的代码只需访问MyClass.myobj字段,而代码本身保留单例行为。当然,使用public static final字段可以实现类似的效果。

枚举的好处是编译器知道你不想意外地创建任意对象。它有一个缺点,如果你想要延迟初始化,你需要为懒惰加载的部分引入一个额外的委托。

答案 4 :(得分:0)

加载MyClass后,它将被初始化。但它只会初始化一次。

答案 5 :(得分:0)

说一个类在加载后立即初始化是不正确的。只有在正在运行的程序创建该类的实例(通过使用new关键字调用其构造函数)或者使用属于该类的任何静态方法或字段时,才会初始化类。

有关初始化的JVM规则,请参阅Java Language Specification section 12.4.1

我应该指出,我只知道这要归功于Joshua Bloch的优秀着作“Effective Java,Second Edition”。第71项提供了有关延迟初始化和“延迟初始化持有者类习惯用语”的建议。

因此,在回答您的问题时,MyClass.myobj只会在正在运行的程序(例如您的main()方法)实际调用MyClass.getMyobj()而不是之前的某个时刻进行初始化然后

因为静态字段每个类只初始化一次,所以下次调用MyClass.getMyobj()时,它只会返回MyClass.myobj的现有值,因此您将获得两个完全相同的MyClass的引用对象