为什么变量初始化为赋值表达式[String x =(x = y)]编译?

时间:2015-06-14 12:59:32

标签: java

如何编译没有错误?根据我的理解,编译器会检查变量的类型(在本例中为String),然后查看右侧表达式的类型是否与变量的类型(或至少是一个子类型)相对应但是,让我们坚持String类的简单案例,因为它是最终的。

public class InitClass {
  public static void main(String[] args) {
    String str = (str = "hello");
    System.out.println(str);
  }
}

我的问题是str = "hello"如何编译?编译器是否已经知道str的类型应为String

3 个答案:

答案 0 :(得分:15)

评估assignment expression

  

首先,评估左侧操作数以生成变量。 If   此评估突然完成,然后是赋值表达式   因同样的原因突然完成;右手操作数不是   评估并且没有分配。

产生变量str。然后

  

否则,评估右侧操作数。如果这个评价   突然完成,然后赋值表达式突然完成   出于同样的原因,没有任何转让。

在您的示例中,右侧操作数本身是另一个赋值表达式。因此,str,赋值运算符的右手操作数,再次被计算以生成变量str。然后

  

否则,右侧操作数的值将转换为   左侧变量的类型,进行值集转换   (§5.1.13)到适当的标准值集(不是   扩展指数值集),和转换结果   存储在变量中。

因此"hello"存储在str中。 And since

  

在运行时,赋值表达式的结果是值   分配发生后的变量。一个结果   赋值表达式本身不是变量。

"hello"分配给str的结果是值"hello",该值再次存储在str中。

答案 1 :(得分:5)

您的情况相当于

String str;
str = (str = "hello");

虽然作业看起来很滑稽,但从概念上来说并没有错。

然而,引用自身的变量初始化显然不是一个好主意。编译器将尝试在很可能是程序错误的情况下标记它;编译器有时无法这样做;并且可能还会在其他时间过火。

局部变量具有更严格的要求(比字段变量更大) - 必须在使用其值之前先分配它。例如,这不会编译,因为本地var在被分配之前被读取。

String str;  // local variable
str = str;   // error, try to read `str` before it's assigned

字段变量始终具有默认初始值;尽管如此,编译器会检查明显的程序错误

int x = x+1;  // error. x is field variable.

但如果此类检查失败,那么这不是灾难性的,因为x在明确分配之前具有值0

int x;
{ x=x+1; } // ok. x==0, then x==1 after assignment

但是,如果xfinal,则上述代码失败,因为编译器在读取x之前需要先明确赋值x,对局部变量的要求相同。但是这种检查可以被规避,因为它不可能完全分析并完全阻止它用于场变量

final int x = (this).x+1;  // compiles!

在某些情况下,编译器过分,阻止涉及lambda的合法用例

Runnable r1 = ()->System.out.println(r1);  // r1 is a field variable 

在这个用例中,概念上没有任何问题;它也可以被(this).规避。

答案 2 :(得分:0)

首先发生的是编译器识别引用的类型然后知道这是一个字符串赋值"你好"到str是有效的。