当前位置: 首页 > 知识库问答 >
问题:

Java Final变量会有默认值吗?

敖毅
2023-03-14

我有一个这样的程序:

class Test {

    final int x;

    {
        printX();
    }

    Test() {
        System.out.println("const called");
    }

    void printX() {
        System.out.println("Here x is " + x);
    }

    public static void main(String[] args) {
        Test t = new Test();
    }

}

如果我尝试执行它,我会得到如下编译器错误:< code >变量x可能没有初始化基于java默认值,我应该得到下面的输出对吗??

"Here x is 0".

最终变量会有默认值吗?

如果我这样更改代码,

class Test {

    final int x;

    {
        printX();
        x = 7;
        printX();
    }

    Test() {
        System.out.println("const called");
    }

    void printX() {
        System.out.println("Here x is " + x);
    }

    public static void main(String[] args) {
        Test t = new Test();
    }

}

我得到的输出是:

Here x is 0                                                                                      
Here x is 7                                                                                     
const called

有人能解释一下这种行为吗。。

共有3个答案

赵景曜
2023-03-14

如果不初始化x,将得到编译时错误,因为x从未初始化。

x 声明为 final 意味着它只能在构造函数或初始值设定项块中初始化(因为编译器会将此块复制到每个构造函数中)。

在变量初始化之前打印出< code>0的原因是由于手册中定义的行为(参见:“默认值”一节):

在声明字段时,并不总是需要赋值。已声明但未初始化的字段将由编译器设置为合理的默认值。一般来说,此默认值将为零或 null,具体取决于数据类型。然而,依赖这样的默认值通常被认为是糟糕的编程风格。

下图总结了上述数据类型的默认值。

Data Type   Default Value (for fields)
--------------------------------------
byte        0
short       0
int         0
long        0L
float       0.0f
double      0.0d
char        '\u0000'
String (or any object)      null
boolean     false
空枫涟
2023-03-14

JLS说你必须将默认值分配给构造函数中的空白最终实例变量(或者在初始化块中,这是完全相同的)。这就是为什么在第一种情况下会出现错误的原因。但是,它并没有说您之前无法在构造函数中访问它。看起来有点奇怪,但你可以在分配之前访问它,并查看int - 0的默认值。

UPD。正如@I4mpi所提到的,JLS定义了一条规则,即每个值都应该在任何访问之前被明确赋值:

每个局部变量(§14.4)和每个空白的最终字段(§4.12.4,§8.3.1.2)在访问其值时必须有明确的赋值。

但是,它在构造函数和字段方面也有一个有趣的规则:

如果C至少有一个实例初始化器或实例变量初始化器,则V在显式或隐式超类构造函数调用后被分配[un],如果V在C最右边的实例初始化器或实例变量初始化器后被分配[un]。

因此,在第二种情况下,值<code>x

叶元凯
2023-03-14

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html,"初始化实例成员"一章:

Java编译器将初始化块复制到每个构造函数中。

也就是说:

{
    printX();
}

Test() {
    System.out.println("const called");
}

行为完全像:

Test() {
    printX();
    System.out.println("const called");
}

如您所见,一旦创建了一个实例,最终字段还没有被明确分配,而(从http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.1.2):

必须在声明它的类的每个构造函数的末尾明确分配一个空的最终实例变量;否则会出现编译时错误。

虽然文档中似乎没有明确说明(至少我找不到它),但最终字段必须在构造函数结束之前临时获取其默认值,以便如果您在分配之前阅读它,它具有可预测的值。

默认值:http://docs . Oracle . com/javase/specs/jls/se7/html/jls-4 . html # jls-4 . 12 . 5

在您的第二个片段中,x在实例创建时初始化,因此编译器不会抱怨:

Test() {
    printX();
    x = 7;
    printX();
    System.out.println("const called");
}

另请注意,以下方法不起作用。只允许通过方法使用 final 变量的默认值。

Test() {
    System.out.println("Here x is " + x); // Compile time error : variable 'x' might not be initialized
    x = 7;
    System.out.println("Here x is " + x);
    System.out.println("const called");
}
 类似资料:
  • 经过在internet上的搜索,我知道了在交互式/非交互式-登录/非登录shell组合的情况下应该在哪里更改PATH变量的值。 从另一个帖子中找到的 我有“/bin/sh”作为缺省登录shell,只有/etc/profile文件用于导出系统中所有需要的环境变量。在非交互式登录shell的情况下,/etc/profile也不会被引用,尽管上面的link说它会被引用。但当我执行时, 我可以看到PATH

  • 行动时刻 - 设置变量的默认值 我们并不总是确定变量是否存在。 Unlang为我们提供了语法,以便在变量不存在时指定默认值。 我们将再次通过修改上一个练习来证明这一点。 我们将使用radtest首先在请求中包含Framed-Protocol = PPP,并将其排除在外。 如果Framed-Protocol AVP不存在,我们将返回一个默认字符串。 编辑FreeRADIUS配置目录下的sites-a

  • 本文向大家介绍Python实例变量的默认值,包括了Python实例变量的默认值的使用技巧和注意事项,需要的朋友参考一下 示例 如果变量包含不可变类型的值(例如字符串),则可以分配这样的默认值 在初始化可变对象(例如构造函数中的列表)时,需要小心。考虑以下示例: 此行为是由于以下事实引起的:在Python中,默认参数是在函数执行时绑定的,而不是在函数声明时绑定的。要获得实例之间不共享的默认实例变量,

  • 我尝试定义一个默认的变量log4j.encodinglog4j2.xml: 我将其用作在运行时解析的变量: 此配置导致以下错误: 但是,当我使用非动态变量(即${sys:log4j.encoding},请注意单个$)时,配置成功,该变量在加载配置文件时计算一次。 默认值对动态变量不起作用是预期行为吗? 详细信息:定义PatternLayout的RollingFile由多个记录器使用。每次加载一个记

  • 问题内容: 我读到Java为类属性提供了默认值,但没有为局部变量提供默认值。那是对的吗?如果是这样,背后的原因是什么?当您做某件事时,为什么不一直这样做呢? 谢谢你, 罗杰 问题答案: 标准局部变量存储在堆栈中,直到初始化后才真正创建。如果未使用局部变量,则它不会进入堆栈。但是,成员变量在堆中分配,因此具有默认的占位符(空引用或默认原语)。

  • 问题内容: 众所周知,根据JLS7 p.4.12.5, 每个实例变量均使用默认值初始化。例如(1): 但是我一直认为,这样的类实现(2): 绝对等于示例(1)。我期望,复杂的Java编译器会看到(2)中的所有这些初始化值都是多余的,并忽略了它们。 但是突然对于这两个类,我们有两个不同的字节码。 例如(1): 例如(2): 问题是: 为什么?但这是显而易见的要优化的事情。什么原因? UPD: 我使用