【问题标题】:Internal working of static and non-static forward references in JavaJava中静态和非静态前向引用的内部工作
【发布时间】:2018-06-12 10:26:58
【问题描述】:

我正在使用 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) {}
}

如果我们打印变量 @987654324 的值,是否有任何类型的临时存储,当我们通过在声明之前分配变量(如上面(1)和(2)步骤中所做的那样)进行前向引用时存储值@,它显示最近分配给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) {}
}

请说明上述两种情况在幕后发生的后台进程。提前致谢! :)

【问题讨论】:

    标签: java static non-static forward-reference


    【解决方案1】:

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

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

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

    • 在C的类变量初始化器或C的静态初始化器中使用简单名称

    • 用法不在作业的左侧;

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

    斜体强调我的)

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

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

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

    • 在C的实例变量初始化器或C的实例初始化器中使用简单名称

    • 用法不在作业的左侧;

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

    斜体强调我的)

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

    【讨论】:

    • 感谢您的回答,但这不是我要求的。我知道 Java 中静态和非静态情况下的前向引用规则,但我问的是如果我使用类名或“this”引用时正在发生的内部过程。使用这两者时会发生什么,以及为什么我们能够实现(以某种方式)与“先声明”规则相矛盾的情况。
    • 理由是这是一种安全措施,不会试图涵盖所有情况。
    【解决方案2】:

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

    当使用简单名称进行前向引用时,静态初始化块中的代码是 也受制于上面讨论的先声明规则。

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

    【讨论】:

    • 感谢您的回答,但这不是我要求的。我知道 Java 中静态和非静态情况下的前向引用规则,但我问的是如果我使用类名或“this”引用时正在发生的内部过程。使用这两者时会发生什么,以及为什么我们能够实现(以某种方式)与“先声明”规则相矛盾的情况。
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2011-09-01
      • 2016-08-07
      • 2013-07-05
      • 1970-01-01
      • 2014-02-19
      • 2015-02-21
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多