将值传递给超构造函数时无法从静态上下文访问字段

Cannot access field from static context when passing value to superconstructor

我遇到了一个非常奇怪的编译时错误:

class Super {
    Super(int[] array) {

    }
}

class Sub extends Super {
    private final int number = 1;

    Sub() {
        super(new int[] { number }); //error
    }
}

我得到的错误是

Cannot access field from static context

我的问题

静态上下文在哪里?似乎 static 甚至不会在这里发挥作用。

我偶然发现了这个试图回答别人问题的问题;发现我莫名其妙的错误。有人可以解释静态上下文在哪里吗?

您的字段 number 应该是静态的,以便您可以在构造函数调用中使用它。否则你会得到 cannot reference number before supertype constructor has been called 因为在调用父 class.

的构造函数之前无法访问该字段

因此您的代码应如下所示:

class Super {
    Super(int[] array) {

    }
}

class Sub extends Super {
    private static final int number = 1;
    Sub() {
        super(new int[] { number }); //error
    }
}

问题是,super 必须在子类中执行任何其他操作之前调用。这意味着 number 在调用时未初始化,因此您不能将其传递给 super。 至于和"static context"有什么关系,我也不清楚。

来自JLS 8.8.7

An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods or inner classes declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.

super 调用时 Sub 的实例尚不存在

尝试运行以下程序。

public class Main {

    public static class Super
    {
        Super(int number) {
            System.out.println("A");
        }
    }

    public static class Sub extends Super {

        private final Thing thing = new Thing();

        Sub() {
            super(3);
            System.out.println("B");
        }
    }

    public static final class Thing {
        Thing() {
            System.out.println("C");
        }
    }

    public static void main(String[] args) {
        new Sub();
    }
}

输出A、C、B。先运行Super的构造函数,然后初始化Sub的实例字段thing。最后 Sub 构造函数中跟随 super 的行被执行。

当您尝试引用 number 时,字段 number 尚未初始化并且没有 Sub 实例。错误消息可能更有帮助。在 IntelliJ 上,我得到 "Cannot reference Sub.number before supertype constructor has been called"。

classes 的加载是从子 class(如果它有 main 方法或由其他 class 加载)到基础 class 但 初始化以相反的顺序发生(基础class将首先初始化)。 base class 初始化已经完成,那时你的数字字段将不存在,因为它是实例变量。

你可以让它 static(class variable) 加载得更早,如果它的 final 那么编译器会做一个在编译时 常量池 中的条目 only.so JVM 将能够获取其值。