gpt4 book ai didi

java - Java 中的 FINAL 变量保存两个不同的值

转载 作者:行者123 更新时间:2023-11-30 01:43:12 25 4
gpt4 key购买 nike

我有以下两个案例。

情况1:

class A{
A(){
System.out.println("A's Constructor");
f();
}
void f() {System.out.println("A");}
}

class B extends A{
B(){
System.out.println("B's Constructor");
f();
}
final String x = "B";
void f() {System.out.println(x);}
}

public class JavaPOCSamples {
public static void main(String[] args) {
new B();
}
}

情况2:

class A{
A(){
System.out.println("A's Constructor");
f();
}
void f() {System.out.println("A");}
}

class B extends A{
B(){
System.out.println("B's Constructor");
f();
}
final String x = "B".trim();
void f() {System.out.println(x);}
}

public class JavaPOCSamples {
public static void main(String[] args) {
new B();
}
}

情况 1 和情况 2 之间的区别在于,情况 2 在 class B 中具有 final String x = "B".trim(),但情况 1 在 class B 中具有 >B 类 中的最终字符串 x = "B"

情况1的输出:

A's Constructor
B // Note that a final variable X is "B"
B's Constructor
B // Note that a final variable X is still "B"

情况2的输出:

A's Constructor
null // Note that a final variable X is null
B's Constructor
B // Note that a final variable X is changed to "B"

问题是关于情况 2 的输出:为什么 final String x 包含两个不同的值,一个是 null,另一个是字符串“B”?

最佳答案

这是一个很好的谜题,涉及 Java 的 final 字段语义和实例创建语义的细节。与任何其他字段一样,final 字段在创建对象时会初始化为默认值 ( JLS §4.12.5 ):

Every variable in a program must have a value before its value is used:

  • Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2):

final 只是一个编译时检查,以确保在创建对象时为该字段赋值一次。在运行时,该字段在被分配新值之前仍然具有默认的初始值。但是,原始类型或 String 类型的 final 变量有一种特殊情况,其初始值设定项是常量表达式 ( §4.12.4 ):

A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28). Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9), and definite assignment (§16 (Definite Assignment)).

常量表达式在 ( §15.28 ) 中定义,以包含文字(包括 String 文字),例如 "B"。表达式"B".trim()是方法调用表达式,因此它不是常量表达式。

剩下的细节是,当创建 B 的实例时,B() 构造函数会隐式调用父类(super class)构造函数 A() ,并且这发生在执行 B() 构造函数的其余部分或子类 B 中的任何初始化程序之前( §12.5 ,强调我的):

Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure: ...

  1. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). ...

  2. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class.

因此,在情况 2 中,因为赋值 x = "B".trim() 位于子类 B 中,所以直到 之后才会执行A() 构造函数已完成。由于 A() 构造函数调用 f(),该方法会打印出 null 值,因为这是该字段之前的默认值被分配了任何其他值。

但是,在情况 1 中,适用使用常量表达式初始化的 String 类型的 final 字段的特殊规则,因此 x 为在调用 A() 构造函数之前已经 "B"

关于java - Java 中的 FINAL 变量保存两个不同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59216143/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com