我正在使用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)步骤中完成声明之前将变量分配给我们进行前向引用时存储值1}},它显示了最近一次分配对c
所做的值。
非静态转发参考
sf1
请介绍上述两种情况后幕后发生的后台流程。提前致谢! :)
答案 0 :(得分:2)
JLS, Section 8.3.3,说明了对静态变量(“类变量”)进行前向引用的条件是编译器错误,尽管它没有说明推理。
使用类变量,其声明在使用后以文本形式出现有时受到限制,即使这些类变量在范围内(第6.3节)。具体来说,如果满足以下所有条件,则为编译时错误:
在使用类变量后,类或接口C中的类变量声明以文本形式出现;
在C的类变量初始值设定项或C的静态初始化程序中使用简单名称;
使用不在作业的左侧;
C是封闭使用的最里面的类或接口。
( italic 强调我的)
实例变量转发参考错误出现时具有类似条件:
使用在使用后以声明方式显示声明的实例变量有时会受到限制,即使这些实例变量在范围内也是如此。具体来说,如果满足以下所有条件,则为编译时错误:
在使用实例变量后,类或接口C中的实例变量声明以文本形式出现;
在C的实例变量初始值设定项或C的实例初始化程序中使用简单名称;
使用不在作业的左侧;
C是封闭使用的最里面的类或接口。
( italic 强调我的)
在这两种情况下,使用简单名称是关键条件。这意味着使用不带任何限定符的变量,例如this
或类名。这就是this.nsf1
在NonStaticForwardReferences
中有效的原因。如果删除this
,则会发生错误。这也是sf1
出错并且StaticForwardReferences.sf1;
没有错误的原因。
答案 1 :(得分:0)
Java要求字段的声明必须在任何初始化程序中使用之前发生 表达式,如果在初始化程序中的赋值的右侧使用该字段 表达。这实质上意味着字段的声明必须在之前发生 在初始化表达式中读取字段的值。
使用简单名称进行正向引用时,静态初始化程序块中的代码是 也受上文讨论的阅读前声明规则的约束。
在实例初始化表达式中,关键字" this"和"超级"可以用来 引用实例初始化程序块中的当前对象。
答案 2 :(得分:0)
禁止前向引用并不意味着在初始化时创建变量。 “后台进程”就是一次性分配类和对象,给出(静态)变量default values。 (也就是说“零”:它可能在实践中用calloc
或memset
实现。)
前向引用规则为meant,以防止看到这些第一个值,尤其是对于final
变量,这些变量应该只有一个值。但它们存在以捕获人为错误并且本身并不完美:仅对于常量变量,初始化发生so early默认值是不可观察的。明确指定this
或类名是证明这种效果的最简单方法。