栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

最终的定义不正确吗?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

最终的定义不正确吗?

一个非常有趣的发现。要理解它,我们需要深入研究Java语言规范(JLS)。

原因是

final
只允许一次 分配 。但是,默认值为no Assignment 。实际上,每个 这样的变量
(类变量,实例变量,数组组件)从一开始就在 赋值 之前指向其 默认值 。然后,第一个分配更改参考。 __


类变量和默认值

看下面的例子:

private static Object x;public static void main(String[] args) {    System.out.println(x); // Prints 'null'}

我们没有为明确分配值

x
,尽管它指向
null
,这是默认值。将其与§4.12.5进行比较:

变量的初始值

每个 类变量* ,实例变量或数组组件在 创建 时都会用 默认值
初始化(第15.9节,第15.10.2节)
*

请注意,这仅适用于此类变量,例如在我们的示例中。它不适用于局部变量,请参见以下示例:

public static void main(String[] args) {    Object x;    System.out.println(x);    // Compile-time error:    // variable x might not have been initialized}

在同一JLS段落中:

必须在使用 局部变量
(第14.4节,第14.14节)之前通过初始化(第14.4节)或赋值(第15.26节)为它
明确赋一个值
,并且可以使用确定赋值规则(第§)进行验证。16(确定分配))。


最终变量

现在

final
,从§4.12.4看:

最终 变量

可以将变量声明为 final 。甲 最终 变量可以仅 分配给一次 。如果将 最终 变量赋值给它,则是编译时错误,除非在
赋值之前绝对未赋值 最终
变量(第16节(确定赋值))。


说明

现在回到您的示例,稍作修改:

public static void main(String[] args) {    System.out.println("After: " + X);}private static final long X = assign();private static long assign() {    // Access the value before first assignment    System.out.println("Before: " + X);    return X + 1;}

它输出

Before: 0After: 1

回想一下我们学到的东西。在方法

assign
的变量
X
没有分配 的值呢。因此,由于它是 类变量
,因此它指向其默认值,并且根据JLS,这些变量总是立即指向其默认值(与局部变量相反)。在该
assign
方法之后,将为变量
X
分配值,
1
并且由于
final
我们无法再对其进行更改。因此,由于以下原因,以下操作将不起作用
final

private static long assign() {    // Assign X    X = 1;    // Second assign after method will crash    return X + 1;}

JLS中的示例

感谢@Andrew,我找到了一个JLS段落,它完全涵盖了这种情况,它也演示了这一点。

但是首先让我们看一下

private static final long X = X + 1;// Compile-time error:// self-reference in initializer

为什么不允许这样做,而从方法中访问却是允许的呢?看看第8.3.3节,它讨论了如果尚未初始化字段时何时限制对字段的访问。

它列出了一些与类变量相关的规则:

对于简单地引用

f
在class或interface中声明的类变量的引用, 如果出现 以下情况
C
,则是 编译时错误

*该引用出现在(§8.7)的类变量初始化器

C
或静态初始化器中。和
C

  • 该引用显示在
    f
    自己的声明器的初始化程序中,或者出现在声明器的左侧
    f
    ;和

*该引用不在赋值表达式的左侧(第15.26节);和

  • 包含引用的最里面的类或接口是
    C

很简单,

X = X + 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);    }}

产生输出:

0

因为变量初始化器

i
使用类方法peek来访问变量的值,
j
然后
j
变量初始化器才对其进行了初始化,此时它 仍然具有其默认值
(第4.12.5节)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/410564.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号