为什么“ String variableName = variableName = value;”在J ava中工作?

问题描述 投票:0回答:2

为什么T variableName = variableName = value;在Java中起作用?其中T可以是任何类型,甚至可以是原始类型。

Integer v1 = v1 = 1;有效。这是否意味着变量声明在语句中具有最高优先级?您能否解释其背后的技术性?

注意:整个问题已被重构/更新。下面的某些评论可能与上下文无关。

java variable-declaration
2个回答
-1
投票

@SSP的发布链接旁边,有一种方法可以查看JShell在幕后的行为。

切换常规调试信息(使用/help /debug获取所有选项)

jshell> /debug
|  Debugging on

现在执行您的语句并打印生成的类

jshell> String foo = foo
class $JShell$11 {
    public static String foo;
    public static Object do_it$() throws Throwable {
        String foo_ =
        foo;
        return foo = foo_;
    }
}

这解释了语句的jhelljavac的不同行为。


-1
投票

我将尝试回答这个问题。我应该确定,这个答案是基于对编程语言通常如何工作的一般知识而不是对Java规范的特定知识的猜测。

首先,我可以确认这种情况出现在编译的Java中,而不仅仅是JShell。

这是我想发生的事情:

这是否意味着变量声明在语句中具有最高优先级?

(可能还有-参见下面@ user207421的有用注释)的排序。

我们必须考虑编译器如何将此代码转换为可操作的机器代码。通常,语言使用stack管理local内存,每个方法/函数调用都会在堆栈的顶部分配新的内存区域(frame)。当函数退出时,将弹出堆栈,并释放该内存区域。为了高效运行,大多数语言都要求知道在编译时特定功能的堆栈帧需要多少内存。这样,在运行时构建和释放堆栈不需要(或很少)分支代码。

编译器如何计算每个堆栈帧需要多少内存?简而言之,该函数主体中声明的每个参数和局部变量都需要足够的空间。

因此,在运行时调用函数时,整个帧的足够内存分配在堆栈的顶部,每个变量和参数都有一个空间。这意味着在运行时,只要包含其功能的代码开始运行,便会有效地“声明”每个变量,因此该变量的任何assignement(即=)在函数执行期间的任何时候都是内存安全的体。

因此T x = x = <some value>非常安全。右边的分配首先发生,而左边的分配(实际上是无操作)发生在第二。出于所有实际目的,声明T x被提升到整个函数的顶部,因此定义发生了[[even firster。]为什么感到困惑?

通常,我们倾向于说类似

“在声明变量之前不能使用变量”]]之类的东西。但是实际上这是一个过分概括的内容,涵盖了两件事:

    未分配存储空间时无法读取或写入变量

  • 变量
  • 应该在首次分配
  • 之前不被读取上面基本满足了第一个要求。

    第二个要求是强制执行逻辑一致性-如果尚未分配变量,则表示该变量的内存段可能无法包含有用的值,因此读取它将是逻辑错误。该规则由编译器在语义上强制执行。没有任何需要执行(特别是对于原语的)的理由,但它表示逻辑错误,或更糟糕的是,安全漏洞。但是,代码T x = x = <some value>不会违反此规则。第一次x

    read是在左侧分配期间发生的,这是在右侧分配之后发生的。像boolean x = x == true这样的替代语句确实无法编译。这只会给我们带来更多需要考虑的事情。像这样的代码有什么问题:

    x = 7; int x;

    从运行时的角度来看,这里没有什么错。但是,这使编译器的工作更加困难。为了执行类型检查,编译器必须先读取声明int x;,才能确定x = 7;是有效的语句。这是主要的

    technical原因,我可以想到为什么语言规范将要禁止此类代码。

    有效地,我们是在说:

    变量声明在运行时被提升到函数的顶部,但是必须在编译时对该变量进行任何引用之前发生。

    还有另一个简单的原因,可能导致人们在首次分配变量后不希望声明该变量:这会使代码难以理解。出于同样的原因,人们可能会争辩说也应该禁止类似T x = x = <some value>的语句,但显然,语言设计者要么不同意,要么没有想到。

    © www.soinside.com 2019 - 2024. All rights reserved.