为什么这段Java代码可以编译?

2024-03-27

在方法或类范围内,下面的行将进行编译(带有警告):

int x = x = 1;

在班级范围内,变量获取默认值的地方,以下给出“未定义的引用”错误:

int x = x + 1;

这不是第一个吗x = x = 1应该最终出现相同的“未定义引用”错误吗?或者也许是第二行int x = x + 1应该编译吗?或者我缺少什么?


tl;dr

For fields, int b = b + 1是非法的,因为b是非法的前向引用b。你实际上可以通过写来解决这个问题int b = this.b + 1,编译时没有任何抱怨。

For 局部变量, int d = d + 1是非法的,因为d使用前未初始化。这是not字段的情况就是这样,它们总是默认初始化的。

您可以通过尝试编译来看到差异

int x = (x = 1) + x;

作为字段声明和局部变量声明。前者会失败,但后者会成功,因为语义上的差异。

介绍

首先,字段和局部变量初始值设定项的规则非常不同。因此,这个答案将分两部分解决规则。

我们将在整个过程中使用这个测试程序:

public class test {
    int a = a = 1;
    int b = b + 1;
    public static void Main(String[] args) {
        int c = c = 1;
        int d = d + 1;
    }
}

的声明b无效并失败并显示illegal forward reference error.
的声明d无效并失败并显示variable d might not have been initialized error.

这些错误不同的事实应该暗示错误的原因也不同。

Fields

Java 中的字段初始值设定项由以下规则控制JLS §8.3.2 http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3.2,字段初始化。

The scope字段的定义是JLS §6.3 http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.3,声明的范围。

相关规则是:

  • 成员声明的范围m在类类型 C 中声明或继承的类型 C(第 8.1.6 节)是 C 的整个主体,包括任何嵌套类型声明。
  • 实例变量的初始化表达式可以使用在类中声明或继承的任何静态变量的简单名称,即使其声明在文本上稍后出现。
  • 其声明在使用后以文本形式出现的实例变量的使用有时会受到限制,即使这些实例变量在作用域内。有关管理对实例变量的前向引用的精确规则,请参阅第 8.3.2.3 节。

§8.3.2.3 说:

成员的声明需要以文本形式出现在之前 仅当成员是实例(分别是静态)字段时才使用 类或接口 C 并且满足以下所有条件:

  • 该用法发生在 C 的实例(分别为静态)变量初始值设定项或 C 的实例(分别为静态)初始值设定项中。
  • 用法不在赋值的左侧。
  • 用法是通过一个简单的名称。
  • C 是包含用法的最内部类或接口。

实际上,您可以在声明字段之前引用字段,但某些情况除外。这些限制旨在防止类似的代码

int j = i;
int i = j;

从编译。 Java 规范表示“上述限制旨在在编译时捕获循环或其他格式错误的初始化。”

这些规则实际上归结为什么呢?

简而言之,规则基本上是说你must如果 (a) 引用位于初始值设定项中,(b) 引用未分配给,(c) 引用是一个,则在对该字段的引用之前声明该字段简单的名字(没有像这样的限定符this.) 和 (d) 它不是从内部类内部访问的。因此,满足所有四个条件的前向引用是非法的,但至少在一个条件上失败的前向引用是可以的。

int a = a = 1;编译是因为它违反了 (b):引用a is被分配给,所以引用是合法的a提前的a的完整声明。

int b = this.b + 1也可以编译,因为它违反了 (c):引用this.b不是一个简单的名称(它的限定条件是this.)。这个奇怪的结构仍然是完美定义的,因为this.b其值为零。

因此,基本上,初始化器中对字段引用的限制会阻止int a = a + 1从成功编译开始。

观察字段声明int b = (b = 1) + b will fail编译,因为最终b仍然是非法的前向引用。

局部变量

局部变量声明受以下约束JLS§14.4 http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.4,局部变量声明语句。

The scope局部变量的定义在JLS §6.3 http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.3, 声明范围:

  • 块中局部变量声明的范围(第 14.4 节)是该声明出现的块的其余部分,从其自己的初始值设定项开始,并包括局部变量声明语句右侧的任何其他声明符。

请注意,初始值设定项位于所声明的变量的范围内。那么为什么不呢int d = d + 1;编译?

原因是Java的规则明确的分配 (JLS §16 http://docs.oracle.com/javase/specs/jls/se7/html/jls-16.html)。明确赋值基本上是说,对局部变量的每次访问都必须先对该变量进行赋值,并且 Java 编译器会检查循环和分支以确保赋值always发生在任何使用之前(这就是为什么明确赋值有一个专门的规范部分)。基本规则是:

  • 对于局部变量或空白最终字段的每次访问x, x必须在访问之前明确赋值,否则会发生编译时错误。

In int d = d + 1;,访问d很好地解析为局部变量,但是因为d之前没有被分配过d被访问时,编译器会发出错误。在int c = c = 1, c = 1首先发生,这会分配c, 进而c被初始化为该赋值的结果(即 1)。

请注意,由于明确的赋值规则,局部变量声明int d = (d = 1) + d; will编译成功(unlike字段声明int b = (b = 1) + b), 因为d肯定是在决赛时分配的d到达了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么这段Java代码可以编译? 的相关文章

  • 我可以在 Java 枚举上使用构建器模式吗

    我正在重写一些代码 并且我已经决定了重新创建类的方法 因为有固定数量的工作表 我将它们创建为枚举 这是基于构建器模式与伸缩构造器的可读性的决定 我的代码获取一些 xls 文件 添加标题 并从其他 xls 文件中读取一些 也许还有一些子表 然
  • Spring Security 自定义身份验证 - AuthenticationProvider 与 UserDetailsS​​ervice

    据我所知 当您想要在 Spring Security 中进行自定义身份验证时 您可以实现自定义AuthenticationProvider或定制UserDetailsService Autowired public void configu
  • string.split("(?!^)") 解释

    我正在尝试将字符串的字符拆分为字符串数组 我找到了解决方案here https stackoverflow com questions 5235401 split string into array of character strings
  • 相当于 java PBKDF2WithHmacSHA1 的 Python

    我的任务是构建一个 API 的使用者 该 API 需要带有 UNIX 时间种子值的加密令牌 我看到的示例是使用我不熟悉的 Java 实现的 在阅读文档和其他堆栈文章后一直无法找到解决方案 使用javax crypto SecretKey j
  • 我需要在 Java 9 中使用哪个模块才能使用 JPA?

    我正在使用一个需要 JPA 的项目测试 Java 9 javax persistence 类 当我添加module info java并声明我的模块 下的所有类javax persistece包变得不可用 我搜索了很多 但找不到在 Java
  • selenium 2.0 中的 isElementPresent

    大家好 我正在使用 webdriver 所以如果我想使用 selenium s rc 函数 isElementPresent 我必须模拟 selenium rc 所以我会执行以下操作 import org openqa selenium B
  • Java:等于和==

    让我们看看我们有 2 个对用户定义类实例的引用 即 Java 中的 a 和 b 会不会有一种情况 a b 但 a equals b 返回 false 当然 实施 equals 完全取决于班级 所以我可以写 class Foo public
  • Java:将二维字符串数组打印为右对齐表格

    是什么best打印a的单元格的方法String 数组作为右对齐表 例如 输入 x xxx yyy y zz zz 应该产生输出 x xxx yyy y zz zz 这似乎是一个should能够完成使用java util Formatter
  • 使用 SSL 和代理设置的 Rest 客户端获取连接超时

    我正在使用带有忽略 ssl 的 Rest 客户端 它工作正常 但在将来我尝试使用客户端证书进行的生产中将无法工作 我有 ca 证书和客户端证书 我用它创建了一个客户端 但我收到错误 Exception in thread main com
  • Java:从 ScriptEngine javascript 返回一个对象

    我正在尝试使用 Java 来评估 javascript脚本引擎 https docs oracle com javase 7 docs api javax script ScriptEngine html班级 这是我正在尝试做的事情的一个简
  • 对象映射器 - YAMLFactory - 由于缺少 _createContentReference 方法而出现异常

    我正在使用最新的 2 13 0 版本的 jackson 当我尝试解析 YAML 文件时 出现此异常 java lang NoSuchMethodError com fasterxml jackson core io ContentRefer
  • 如何在 PuTTY 中保存并运行 Java 文件?

    我是 AWS 亚马逊网络服务 的新手 所以这可能是一个基本问题 我在 AWS 上创建了一个 EC2 实例 我有一台 Windows 计算机 因此我使用 PUTTY 来连接 Linux 实例 连接到我的 EC2 实例后 我使用以下命令编写 J
  • Netty Nio java 中的通信

    我想在 Netty nio 中创建一个具有两个客户端和一个服务器的通信系统 更具体地说 首先 我希望当两个客户端与服务器连接时从服务器发送消息 然后能够在两个客户端之间交换数据 我正在使用本示例提供的代码 https github com
  • 从 Java 应用程序读取的文件是否会调用系统调用?

    我的理解是 请求文件系统路径 例如 aFile 的用户应用程序将调用文件系统并获取所请求文件的虚拟地址 然后应用程序将尝试以该地址作为参数 即作为 CPU 指令 进行读 写操作 执行读取命令时 内存管理单元会将该地址转换为物理地址 并查看页
  • AWS SQS Batch SendMessageBatchRequest 非常慢

    我的应用程序使用 SendMessageBatchRequest 将每个请求发布 10 条消息到 AWS SQS 每条消息的大小小于250字节 该应用程序预计每天发布约一百万条记录 但要实现这一目标 消息发布的速度非常慢 AmazonSQS
  • Java 执行器和长寿命线程

    我继承了一些使用 Executors newFixedThreadPool 4 的代码运行 4 个长寿命线程来完成应用程序的所有工作 这是推荐的吗 我读过Java 并发实践 https rads stackoverflow com amzn
  • 可空日期列合并问题

    我在 Geronimo 应用程序服务器上使用 JPA 和下面的 openjpa 实现 我也在使用MySQL数据库 我在更新具有可为空 Date 属性的对象时遇到问题 当我尝试合并 Date 属性设置为 null 的实体时 不会生成 sql
  • 为什么 OOP 中静态类的最佳实践有所不同?

    我目前正在阅读有关 Java 最佳实践的内容 我发现根据这本书 https rads stackoverflow com amzn click com 0321356683我们必须优先选择静态类而不是非静态类 我记得在 C 最佳实践中 我们
  • 如果 @transactional 在类级别应用,如何拦截 @transactional 参数

    我想捕获 transactional 的参数 如果它应用于类级别 例如如果 transactional应用在方法级别 例如 class A transactional readOnly true public void someMethod
  • Bipush 在 JVM 中如何工作?

    我知道 iload 接受整数 1 到 5 但是如何使用 bipush 指令扩展到更高的数字 特定整数如何与字节码一起存储 有几种不同的指令可用于推送整数常量 最小的是iconst 指令 这些只是一个字节 因为该值是在操作码本身中编码的 ic

随机推荐

  • iOS:使用全屏图像构建幻灯片

    我想构建一个幻灯片 您可以在其中滑动图像 以全屏模式显示 我打算使用 UIViews 并添加手势识别器 但我想知道是否有一些已经完成的事情我可以重用 或者任何提示 我希望获得与您在 iPad 上滑动打开的应用程序时相同的效果 您可以滑动它们
  • 如何在 Python 中使用 OpenCV 跟踪运动?

    我可以使用我的网络摄像头获取帧OpenCV http opencv willowgarage com wiki 在Python中 camshift 示例接近我想要的 但我不希望人为干预来定义对象 我想获得在几帧的过程中变化的总像素的中心点
  • VS2017 在源代码中出现大量“无法解析符号”错误,但一切都构建完成

    我在 VB Net 源代码文件中收到大量 无法解析符号 错误 解决方案中的所有内容都可以毫无问题地构建 Peek Definition 和 Goto Implement 工作正常 到目前为止 我已经尝试过以下操作 进行过构建吗 清理 关闭
  • 理解 find 中转义的括号

    我已经拼凑了下面的内容 它似乎可以工作 但 空 可能是个例外 我正在学习的一件事 随着我的学习 是 仅仅因为某些东西有效 并不意味着它是正确的或正确形成的 我的问题是如何确定查找中哪些需要括号 哪些不需要命令 在 OS X 中 and 是
  • Python类装饰器扩展类导致递归

    我正在覆盖 a 的保存方法ModelForm我不知道为什么它会导致递归 parsleyfy class AccountForm forms ModelForm def save self args kwargs some other cod
  • matplotlib 中的散点图

    这是我的第一个 matplotlib 程序 很抱歉我的无知 我有两个字符串数组 说 A test1 test2 and B test3 test4 如果之间存在任何相关性A and B元素 它们的 corr 值将被设置为1 test1 te
  • ClearCase 的“MVFS 文件系统”的本质是什么?

    Clearcase 服务器中的 MVFS 有何作用 MVFS 多版本文件系统 并不是 创建 文件系统 而是让您访问一个文件系统 M 在 Windows 上 或 view 在 Unix 上 是一个安装点 允许浏览您安装的任何 Vob Clea
  • 更改 xml 节点中的值时出错

    我需要更改 xml 的多个值 但是当我运行 setText 行时 它显示 java lang NullPointerException 错误 我不明白为什么
  • 如何在MySQL中找到当前用户连接的IP地址?

    在您回答 use current user 这在很多情况下都有效 或 use user 这实际上不起作用 之前 请阅读以下内容 我正在尝试在表上创建一个视图 该视图限制用户对表中某些行的访问 并由用户连接的 IP 地址控制 我的第一次尝试是
  • React Native 如何获取“getPackageManager()”

    你知道如何在react native中访问 getPackageManager 对于java 吗 我到处搜索 但只发现 getPackageManager 的一些错误 我需要它来知道我的应用程序是否已从 Play 商店或通过其他方法下载 我
  • Android appWidget 多个实例

    这个问题几乎是重复的Android 多个appWidgets播放不同的声音 https stackoverflow com questions 4225197 android multiple appwidgets playing dife
  • cvc-elt.1:找不到元素“MyElement”的声明

    我正在尝试使用 xsd 验证一个非常简单的 xml 但由于某种原因我收到此错误 如果有人能向我解释原因 我将非常感激 XML File
  • ngx/translate - 仅翻译字符串的一部分

    我需要使用翻译来自服务器的字符串ngx 翻译 https github com ngx translate core 当我需要翻译字符串时它工作得很好 但在某些情况下我只需要翻译字符串的一部分 例如 你好谢伊 或 你好约翰 我只需要翻译 你
  • 将数据透视缓存从一个文件上的数据透视传输到另一个文件上的数据透视?

    我需要将 Excel 文件上的数据透视表的缓存安全地传输到另一个文件上的数据透视表中 我怎样才能做到这一点 这是我现在使用的代码 请注意 即使源数据透视数据源已被消除 此方法仍然有效 Public Sub TransferPivotCach
  • Rails 重命名协会

    我有两个模型 TreeNode 和 User 每个用户has oneTreeNode 即树的根 class TreeNode acts as tree belongs to user end class User has one tree
  • Django manage.pysyncdb 抛出 No module named MySQLdb

    我是一个学习Python Django的新手 我正在使用以下教程here http docs djangoproject com en dev intro tutorial01 intro tutorial01 在 Snow Leopard
  • TerminateProcess 不适用于经过验证的进程 ID

    我正在开发应该杀死具有给定名称的进程的应用程序 我使用的操作系统是 Windows 7 问题是 对于任务管理器中列出的具有非空白用户名字段的所有进程 它都可以正常工作 但是 当进程的用户名为空时 即使任务管理器也无法杀死该进程 谁能告诉我为
  • 用法:java cucumber.api.cli.Main [选项] [ [FILE|DIR][:LINE[:LINE]*] ]+

    我在运行功能文件时收到此错误 Usage java cucumber options FILE DIR LINE LINE Options g glue PATH Where glue code step definitions and h
  • PHP MongoDB 使用 $in/$or 更新多个文档

    我无法弄清楚如何在 PHP 中构建更新查询来更新文档 ID X Y 和 Z 有人有这方面的经验吗 ids array new MongoId 4eaaf929498fe2c80300000c new MongoId 4eaaff24498f
  • 为什么这段Java代码可以编译?

    在方法或类范围内 下面的行将进行编译 带有警告 int x x 1 在班级范围内 变量获取默认值的地方 以下给出 未定义的引用 错误 int x x 1 这不是第一个吗x x 1应该最终出现相同的 未定义引用 错误吗 或者也许是第二行int