4

我正在使用 Java 中的前向引用,想知道为什么 Java 允许使用ClassName(在静态变量中)或this在实例变量的情况下使用引用进行前向引用?在 JVM 级别发生的后台进程是什么?例如:

静态前向参考-

class StaticForwardReferences {
    static {
        sf1 = 10;   // (1)
        int b = sf1 = 20;   // (2)
        int c = StaticForwardReferences.sf1; // (3) Works fine
        // Above statement allows the allocation of value of 'sf1'
        // to variable 'c' just because it is accessed with class name
        // instead of direct name

        // whereas below statement throws illegal forward reference
        // error at compile time
        System.out.println(sf1); // (4) Illegal forward reference
    }
    static int sf1 = sf2 = 30;
    static int sf2;

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

是否存在任何类型的临时存储,当我们通过在上面的(1)和(2)步骤中所做的声明之前分配变量来进行前向引用时存储值,如果我们打印变量的值c,它会显示值从最近的作业做到sf1

非静态前向参考-

class NonStaticForwardReferences {
    {
        nsf1 = 10;
        System.out.println(this.nsf1);  // 10
        nsf1 = sf1;
        // System.out.println(nsf1); Illegal forward reference
        int b = nsf1 = 20;

        int c = this.nsf1;
        System.out.println(c);  // 20
        // why variable 'c' is initialized to 20 when used with 'this' reference
        // instead of showing illegal forward reference, how it works in the background?
   }

   int nsf1 = nsf2 = 30;
   int nsf2;
   static int sf1 = 5;

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

请对上述两种情况在幕后进行的后台进程有所了解。提前致谢!:)

4

3 回答 3

2

JLS,第8.3.3 节,说明了对静态变量(“类变量”)进行前向引用的条件是编译器错误,尽管它没有说明推理。

有时限制使用在使用后以文本形式出现声明的类变量,即使这些类变量在范围内(第 6.3 节)。具体来说,如果以下所有条件都为真,则为编译时错误:

  • 类或接口 C 中的类变量声明在使用类变量之后以文本形式出现;

  • use 是C 的类变量初始化器或 C 的静态初始化器中的简单名称

  • 使用不在作业的左侧;

  • C 是包含使用的最内层类或接口。

斜体强调我的)

实例变量前向引用错误出现的情况类似:

有时限制使用在使用后以文本形式出现声明的实例变量,即使这些实例变量在范围内。具体来说,如果以下所有条件都为真,则为编译时错误:

  • 在使用实例变量之后,类或接口 C 中的实例变量的声明以文本形式出现;

  • use 是C 的实例变量初始化器或 C 的实例初始化器中的简单名称

  • 使用不在作业的左侧;

  • C 是包含使用的最内层类或接口。

斜体强调我的)

在这两种情况下,使用简单的名称是这里的关键条件。这意味着使用没有任何限定符(例如this类名)的变量。这就是为什么this.nsf1NonStaticForwardReferences. 如果您删除this,则会发生错误。这也是为什么sf1有错误和StaticForwardReferences.sf1;没有错误的原因。

于 2018-01-02T18:21:26.750 回答
0

如果字段用于初始化表达式中赋值的右侧,Java 要求字段的声明必须在其在任何初始化表达式中的使用之前发生。这实质上意味着必须在初始化表达式中读取字段值之前声明字段。

使用简单名称进行前向引用时,静态初始化程序块中的代码也受上述读取前声明规则的约束。

与实例初始化表达式一样,关键字“this”和“super”可用于引用实例初始化块中的当前对象。

于 2018-01-02T19:03:20.900 回答
0

禁止前向引用并不意味着变量是在初始化时创建的。“后台进程”就是类和对象一次性分配,(静态)变量被赋予默认值。(也就是说“零”:它可能已在实践中实现callocmemset在实践中实现。)

前向引用规则旨在防止看到这些第一个值,尤其是对于final假定只有一个值的变量。但是它们的存在是为了捕捉人为错误并且它们本身并不完美:只有对于常量变量,初始化才会发生 太早,以至于默认值是不可观察的。显式指定this或类名是演示此效果的最简单方法。

于 2018-01-08T22:07:06.313 回答