为什么我的字段为null,即使它应该立即实例化?

时间:2013-10-21 07:43:48

标签: java class field instantiation operator-precedence

我声明并立即实例化的字段为null。以下是示例代码:

public class NullFieldSSCCE {

    static abstract class Parent {
        List<String> values;
        Parent() {
            values = getValues();
        }

        protected abstract List<String> getValues();   
    }

    static class Child extends Parent {

        String param1="test1";
        String param2="test2";

        Child() {
        }

        @Override
        protected List<String> getValues() {
            return Arrays.asList( new String[] {param1, param2} );
        }
    }

    public static void main(String[] args) {
        Child child = new Child();

        System.out.println("Child p1="+child.values.get(0)+", p2="+child.values.get(1));
    }

}

运行它的结果是

Child p1=null, p2=null

虽然我期待

Child p1=test1, p2=test2

这怎么可能?这些字段在课程的同一时刻被实例化,不是吗?

1 个答案:

答案 0 :(得分:7)

发生了什么

8.3.2章节8.8Parent中介绍了您遇到的问题。您可以找到一些不太详细且可能更容易阅读的信息JLS

此处的问题是对象的初始化顺序。

以下是您的示例的初始化顺序:

  1. values字段已实例化:ArrayList成为Child的实例
  2. super()构造函数调用Parent,因此调用getValues()构造函数
  3. Child.getValues()被召唤;在这种情况下,它是Child;
  4. param1字段已实例化:param2Child已分配其值
  5. 4构造函数继续 - 并且在您的情况下不做任何其他事情
  6. 您可以保证同时实例化给定层次结构中所有类的所有字段,31之前发生,并且与printf大致同时发生。遗憾的是,这种假设是错误的。

    学习初始化顺序

    即使您已经阅读了我给您的链接,您也可能无法确定在特定情况下的工作方式。每当您对初始化顺序有疑问时,请不要犹豫,添加public class NullFieldSSCCE { static abstract class Parent { List<String> values = new ArrayList<String>() {{ System.out.println("Parent.values instantiation"); }}; Parent() { System.out.println("Parent()"); values.addAll(getValues()); } protected abstract List<String> getValues(); } static class Child extends Parent { String param1="test1"; String param2="test2"; Object param3 = new Object() {{System.out.println("Child.param3 instantiation"); }}; Child() { System.out.println("Child()"); } @Override protected List<String> getValues() { System.out.println("Child.getValues()"); return Arrays.asList( new String[] {param1, param2} ); } } public static void main(String[] args) { System.out.println("start"); Child child = new Child(); System.out.println("Child p1="+child.values.get(0)+", p2="+child.values.get(1)); } } 来检查它。我这次为你做了这件事:

    start
    Parent.values instantiation
    Parent()
    Child.getValues()
    Child.param3 instantiation
    Child()
    Child p1=null, p2=null
    

    输出是:

    {{1}}