我声明并立即实例化的字段是 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

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

最佳答案

怎么了

您遇到的情况在 8.3.28.8 章节中的 JLS 中进行了描述。您可以找到一些不太详细但可能更容易阅读的信息 here

这里的问题是对象的初始化顺序。

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

  • Parent 字段被实例化:values 成为 ArrayList
  • 的一个实例
  • Child 构造函数调用 super() ,因此调用 Parent 构造函数
  • getValues() 被调用;在这种情况下,它是 Child.getValues()
  • Child 字段被实例化: param1param2 将它们的值分配给
  • Child 构造函数继续 - 在你的情况下什么也不做

  • 您假设给定层次结构中所有类的所有字段都同时实例化,4 发生在 3 之前,并且与 1 大致同时。不幸的是,这种假设是错误的。

    学习初始化顺序

    即使您已经阅读了我给您的链接,您也可能不确定在特定情况下事情会如何运作。每当您对初始化顺序有疑问时,请不要犹豫,添加 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
    

    关于java - 为什么我的字段应该立即实例化,但它为空?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19488746/

    10-11 22:10
    查看更多