在研究另一个问题时,我惊讶地发现以下 Java 代码编译时没有错误:
public class Clazz {
int var = this.var + 1;
}
在我的 JDK6 中,var
初始化为1
.
上述代码是否具有明确定义的语义,或者其行为未定义?如果你说它定义明确,请引用JLS的相关部分。
在 8.3.2.3节的示例 8.3.2.3-1 中顺便提到了它。在示例的文本中
class Z {
static int peek() { return j; }
static int i = peek();
static int j = 1;
}
class Test {
public static void main(String[] args) {
System.out.println(Z.i);
}
}
标题说:
... i 的变量初始化器使用类方法 peek在 j 被其变量初始化器初始化之前访问变量 j 的值,此时它仍然具有其默认值 (§4.12.5) 。
这应该直接映射到您的情况。
允许实例变量的初始化表达式引用当前对象 this(第 15.8.3 节)并使用关键字 super(第 15.11.2 节,第 15.12 节)。
虽然下一段补充说:
有时限制使用在使用后以文本形式出现声明的实例变量,即使这些实例变量在范围内。有关管理对实例变量的前向引用的精确规则,请参见第 8.3.2.3 节。
第 16 章描述了语言确保在使用前明确设置局部变量的精确方法。虽然所有其他变量都会自动初始化为默认值,但 Java 编程语言不会自动初始化局部变量以避免掩盖编程错误。
在按照JSL的情况下,不允许使用简单名称。所以必须使用这个关键字来访问这些变量。forward references
class UseBeforeDeclaration {
int h = j++; // error - `j` read before declaration
int l = this.j * 3; // ok - not accessed via simple name
int j;
}
由于所有非局部变量都被分配了一个初始值(并且分配发生在其他任何事情之前),因此在任何时候读取它们都没有问题。
该规范在某些情况下选择性地禁止某些访问,理由是此类访问很可能是编程错误。但是如果允许这些访问,它们将具有明确定义的语义。
实际上,程序员可以轻松绕过限制并“间接”访问该字段;如果允许,该访问的语义与“直接”访问相同。
int var = this.var + 1; // suppose javac forbids this
int var = this.getVar() + 1; // but can javac forbid this?
这没有错。this 关键字引用当前对象,用于区分局部变量和实例变量。局部变量的值同样可以赋值给实例变量,反之亦然。这意味着我们可以将实例变量的值分配给局部变量。
请参阅http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf中的第4.12.3 章变量种类(第 80 页)。这里也给出了例子。
**Example 4.12.3-1. Different Kinds of Variables**
class Point {
static int numPoints; // numPoints is a class variable
int x, y; // x and y are instance variables
int[] w = new int[10]; // w[0] is an array component
int setX(int x) { // x is a method parameter
int oldx = this.x; // oldx is a local variable
this.x = x;
return oldx;
}
}