Java中的静态初始化?

时间:2017-07-07 09:10:31

标签: java nullpointerexception static-variables

我试图执行以下代码:

public class StaticTest {

    private static List<String> dat1;
    {
        dat1 = new ArrayList<>(); 
    }

    private StaticTest(){
        System.out.println(dat1.contains("a")); //Marked Line 2: this one is not throwing
    }

    public static void main(String[] args) {
        System.out.println(dat1.contains("a")); //Marked Line 1: This line throws null pointer 
        new StaticTest(); 
    }
}

我尝试执行上面的代码,我在Marked Line 1上得到Null pointer exception。但是当我评论Marked Line 1时,我得到了输出。

为什么我在第一种情况下获得异常而不在第二种情况下获得异常?

当我使用private static List<String> dat1= new ArrayList<>();时,不会抛出任何异常。

4 个答案:

答案 0 :(得分:4)

简单:

System.out.println(dat1.contains("a")); 

运行构造函数(因为它在构造函数中!)。 运行构造函数的一部分是:运行类的所有非静态初始化程序块。

鉴于:

public static void main(String[] args) {
  System.out.println(dat1.contains("a")); //Marked Line 1: This line 

只会运行您的静态初始化程序 - 但是没有构造函数代码(确实如此 - 但那行之后)。

所以你的问题是这个初始化程序块:

{
    dat1 = new ArrayList<>(); 
}

不是静态

换句话说:你的问题是由非常不健康的方式混合静态/非静态引起的。如果字段静态,请确保静态初始化代码将初始化它。

顺便说一句:合理的解决办法就是:

private final static List<String> data = new ArrayList<>();

这确保列表尽快初始化;然后编译器会告诉你什么时候忘记初始化它。

答案 1 :(得分:1)

此代码

{
    dat1 = new ArrayList<>(); 
}

此构造函数块。这将在super()之后的每个构造函数中执行,因此它不会在Mark1上运行。

如果你有这样的代码,它将在加载类时执行。

static {
    dat1 = new ArrayList<>(); 
}

这里有更多细节 http://www.jusfortechies.com/java/core-java/static-blocks.php

答案 2 :(得分:1)

您好@kajal请参考以下正确的代码: -

 public class StaticTest {

    private static List<String> dat1;
    static
    {
        dat1 = new ArrayList<String>(); 
    }

    private StaticTest(){
        System.out.println(dat1.contains("a")); //Marked Line 2: this one is not throwing
    }
    public static void main(String[] args) {
        System.out.println(dat1.contains("a")); //Marked Line 1: This line throws null pointer 
        new StaticTest(); 
    }
}

当您创建该类的实例时,将执行实例块。 问你为什么得到NullPointerException: - 请找到StaticTest类执行的以下流程: -

  1. 首先,所有导入类都将加载如下: -
    1. Object第2课。java.lang包类3。java.util.ArrayList类。
  2. 编译器通过StaticTest类并为所有静态成员分配内存 dat1
  3. 现在,javac编译器会搜索执行的静态块。在你的情况下,他们没有静态阻止。
  4. 现在编译器执行main方法并执行System.out.println(dat1.contains("a"));被称为 null.contains("a"); ,它会执行该操作,但正如我所说的实例块执行当您创建该类的实例时。因此,当您创建对象dat1
  5. 时,会初始化 new StaticTest();

答案 3 :(得分:0)

您的代码:

{
    dat1 = new ArrayList<>(); 
}

是非静态初始化程序。当您使用:new StaticTest()调用构造函数时,将调用此方法。之后dat1将被初始化。

您可以将代码更改为静态初始化,方法是将其添加到static关键字:

static
{
    dat1 = new ArrayList<>(); 
}

然后它适用于两种情况。