具有静态默认代码的静态方法



很抱歉标题不好,但我在 mkyoung.com 上找到了下面列出的代码,想知道这段代码是做什么的。这是 Java 中将一些默认值设置为变量的一种方式吗?

public class LanguageBean implements Serializable{
    private static Map<String,Object> countries;
    static{
        countries = new LinkedHashMap<String,Object>();
        countries.put("English", Locale.ENGLISH); //label, value
        countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
    }
}

此位声明一个静态字段:

private static Map<String,Object> countries;

因此,可以直接在课堂上访问它,例如 LanguageBean.countries(或只是countries(,但仅来自类中的代码,因为它是私有的。

此位是静态初始值设定项:

static{
    countries = new LinkedHashMap<String,Object>();
    countries.put("English", Locale.ENGLISH); //label, value
    countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}

它在加载类时运行,在创建任何实例之前,并且确实会向countries添加一些条目。如果有多个静态初始值设定项,则按源代码顺序运行。请参阅本教程中的静态初始值设定项块


FWIW,两者也有每个实例的版本。实例字段:

private int foo;

。和实例初始值设定项;它们看起来有点奇怪,因为它们只是块,块前面什么都没有:

{
    this.foo = 42;
}

在上下文中,并且具有第二个实例成员:

class Thing {
    private int bar = 16; // An initializer on the declaration
    private int foo;
    // An instance initializer block
    {
        this.foo = 42; // Or just foo = 42;, but I prefer to be clear
    }
}

因此,您可以做同样的事情。

基本上是的,它正式称为静态初始值设定项。 并按照 JLS-8.7 静态初始值设定项

在类中声明的静态初始值设定项在初始化类时执行 (§12.4.2(。与类变量的任何字段初始值设定项 (§8.3.2( 一起,静态初始值设定项可用于初始化类的类变量。

这些被称为静态初始化块。

静态初始化块是括在大括号 { } 中的普通代码块,前面是 static 关键字。下面是一个示例:

static {
    // whatever code is needed for initialization goes here
}

一个类可以有任意数量的静态初始化块,它们 可以出现在类主体中的任何位置。运行时系统保证 静态初始化块的调用顺序是按照它们的顺序 出现在源代码中。

静态块还有另一种选择——你可以写一个私有的 静态方法:

class Whatever {
    public static varType myVar = initializeClassVariable();
    private static varType initializeClassVariable() {
        // initialization code goes here
    }
}

私有静态方法的优点是它们可以重用 稍后,如果需要重新初始化类变量。

每当首次初始化类时都会调用它们,并且可用于方便地初始化字段。

声明

Map的静态变量countries使用静态初始值设定项填充。有两个条目正在添加到Map 中。

static{
    countries = new LinkedHashMap<String,Object>();
    countries.put("English", Locale.ENGLISH); //label, value
    countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}

一个效果

静态初始值设定项

它在加载类时运行,并且块是线程安全的,因此它用于设计模式(如singletons等(以减轻线程同步的需求。

有关详细信息,请参阅此线程: Java 静态初始值设定项线程安全吗?

同样的方式看待对象的成员字段。 你可能有这样的东西:

private final Map<String, Object> countries;
public ClassName(){
    countries = new LinkedHashMap<String,Object>();
    countries.put("English", Locale.ENGLISH); //label, value
    countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}

每次将new ClassName()声明为某种"初始"状态时,这将初始化成员字段。 以下:

static{
    countries = new LinkedHashMap<String,Object>();
    countries.put("English", Locale.ENGLISH); //label, value
    countries.put("Chinese", Locale.SIMPLIFIED_CHINESE);
}

。本质上做同样的事情,除了对静态字段执行。 现在,当类被加载时,这个静态块被调用并在使用静态字段之前对其进行初始化,以便它们具有一些"初始"状态。 当您有不会更改的内容(例如,您可能想要设置一个地图,使某些内容的查找变得容易(或当您需要设置可能引发异常但您尝试设置的内容确实应该是静态时,通常会使用此方法,例如:

private static KeyPairGenerator KPG;
static {
    try {
        KPG = KeyPairGenerator.getInstance("RSA");
        KPG.initialize(2048);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        System.err.println("Couldn't get a Key Pair Generator...exiting");
        System.exit(1);
    }
}

在上面的情况下,我只需要一个KeyPairGenerator来管理我的所有类(假设我总是要使用密钥大小为 2048 的 RSA 加密(。 使用这个单一KeyPairGenerator我可以生成多个公钥对。 但是,创建KeyPairGenerator会引发NoSuchAlgorithm异常(这不会发生,因为需要 Java 来支持密钥长度为 2048 的 RSA(。 所以我仍然可以使用此静态初始值设定项获取静态KeyPairGenerator

它用于创建变量并在类加载期间初始化它(那是 static{} 块执行的时候(。

正如Java语言规范所述:

静态初始值设定项 (§8.7( 是可执行代码块,可能是 用于帮助初始化类。

而且它确实常用于小型教程程序中初始化值。

另一方面,它们也用于"更大"的程序。您还可以使用它在工厂对象中注册类。在这种情况下,每个混凝土产品都在工厂注册。通过这样做,您不必在添加新的混凝土产品时修改工厂类。

class OneProduct extends Product
{
    ...
    static
    {
        ProductFactory.instance().registerProduct("ID1", new OneProduct());
    }
    public OneProduct createProduct()
    {
        return new OneProduct();
    }
    ...
}

相关内容

最新更新