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

Java 为什么我的字段为空,即使它应该立即实例化?,java,class,field,instantiation,operator-precedence,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(

我声明并立即实例化的字段是
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=test1, p2=test2
这怎么可能?这些字段在类被实例化的同时被实例化,不是吗?

发生了什么 您遇到的问题在章节
8.3.2
8.8
中进行了描述。您可以找到一些不太详细、可能更容易阅读的信息

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

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

  • Parent
    字段被实例化:
    values
    成为
    ArrayList
  • Child
    constructor调用
    super()
    ,因此调用
    Parent
    构造函数
  • 调用
    getValues()
    ;在本例中,它是
    Child.getValues()
  • Child
    字段被实例化:
    param1
    param2
    已分配其值
  • Child
    constructor继续-在您的情况下不再执行任何操作
  • 假设给定层次结构中所有类的所有字段都是同时实例化的,
    4
    发生在
    3
    之前,大致与
    1
    同时发生。不幸的是,这一假设是错误的

    学习初始化顺序 即使您已经阅读了我给您的链接,您也可能不确定在特定情况下事情将如何运作。当您对初始化顺序有疑问时,请毫不犹豫地添加
    printf
    s进行检查。这次我是为你做的:

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

    您可能会收到关于在构造函数中使用非final方法不好的警告;这是why@RichardTingle没有警告奇怪的是,我在您的SSCCE中收到了“构造函数中的可重写方法调用”警告。你在用什么,IDE还是命令行?@richardingleEclipse4.2.0,JDK7U05i已经做了一些调查,这可能是一个特定于netbeans的提示
    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