静态方法与静态默认代码?

时间:2014-12-15 05:48:09

标签: java

抱歉标题错误,但我在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);
    }
}

6 个答案:

答案 0 :(得分:25)

这个位声明一个静态字段:

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添加了一些条目。如果有多个静态初始值设定项,则它们以源代码顺序运行。请参阅this tutorial中的静态初始化程序块


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
    }
}

所以你可以为实例做同样的事情。

答案 1 :(得分:6)

基本上是的,它正式称为静态初始化程序。并按JLS-8.7 Static Initializers

  

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

答案 2 :(得分:4)

这些被称为Static Initialization Blocks

  

静态初始化块是用大括号{}括起来的常规代码块,前面是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
    }
}
     

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

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

答案 3 :(得分:4)

使用静态初始化程序填充声明为countries的静态变量Map。有两个条目被添加到Map

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

的一个影响
  

静态初始化程序

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

有关详细信息,请参阅此主题:     Are Java static initializers thread safe?

答案 4 :(得分:3)

以与想象对象的成员字段相同的方式来思考它。你可能有这样的事情:

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

答案 5 :(得分:0)

它用于创建变量并在类加载期间初始化它(即当执行static {}块时)。

作为Java语言规范状态:

  

静态初始化器(第8.7节)是可执行代码块   用于帮助初始化一个类。

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

另一方面,他们也可以使用“更大”的程序。您也可以在Factory对象中使用它注册类。在这种情况下,每个具体产品在工厂中注册。通过这样做,您不必在添加新的具体产品时修改工厂类。

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