Java 中的确定赋值2024 年 9 月 10 日 | 阅读 15 分钟 每个局部变量和 final 空白字段在访问任何值时都将具有已分配的值。对值的访问将包括变量名或出现在表达式中的区域,除了赋值运算符 "=" 的左侧操作数。 要访问局部变量或 final 空白字段 x,必须在访问它之前明确为其赋值,否则将发生编译时错误。 同样,每个 final 空白变量将被赋值一次,并在对其进行赋值时未赋值。 因此,此类赋值的定义是仅当变量名出现在赋值运算符的左侧时才发生。 当对 final 空白变量进行赋值时,该变量在此之前不应被赋值,否则将出现编译时错误。 这种明确赋值的主要思想是,局部变量赋值或 final 空白字段的赋值发生在访问的每个可能执行路径上。 因此,分析将考虑表达式和语句的结构,并且将立即处理表达式中的运算符,例如 &&、!、||、? : 以及布尔值常量表达式。 对于像 &&、|| 和 ?: 这样的条件布尔运算符以及布尔值常量表达式,存在一个例外处理,并且表达式的值不会在流分析中考虑。 让我们通过一个例子来讨论这一点。 明确赋值将考虑表达式和语句的结构。Java 编译器将决定在访问“k”之前已为其赋值,就像代码中方法调用的参数一样。 这是因为在表达式的值准确时会发生访问。该值仅在执行并更充分地评估了对“k”的赋值后才有效。表达式如下 同样,Java 编译器将在上述代码中识别出,变量“k”已在 while 语句中明确赋值,因为条件表达式“TRUE”永远不会取“FALSE”的值。break 语句将仅导致 while 语句正常编译,并且变量“k”在 break 语句之前已明确赋值。 而且,另一方面, Java 编译器将拒绝上述代码,因为在上述情况下,如果我们考虑明确赋值规则,while 语句无法正确执行其主体。 另一个例子 Java 编译器将为上述代码生成编译时错误,即使“n”的值在编译时已知。根据规则,在编译时可以知道对值“k”的赋值总是会执行,并且更准确地说,它会执行。 Java 编译器必须遵循我们上面讨论的规则。只有常量表达式遵循规则,而在上面的例子中,常量表达式 n > 2 不是常量表达式。 我们将讨论另一个 Java 编译器将接受代码的示例 只要我们考虑“k”的明确赋值,因为上面的规则已被打破,我们就可以说“k”已经被赋值,无论标志的值是 true 还是 false。 规则将不接受上述变体,程序将收到编译时错误。 明确未赋值的示例就“k”的明确未赋值而言,Java 编译器将接受代码,并且这些交叉的规则将允许它说“k”只赋值一次,无论它是 true 还是 false,这都没有关系。 规则将不接受变体,但当我们编译上述程序时,它会收到编译时错误。 为了指定明确赋值的步骤,这些规则将定义许多技术术语
在布尔值表达式的情况下,上述最后两个步骤被重定向为四个点
从上面可以看出,true 和 false 指的是表达式的值。 让我们举个例子。 只有当上述表达式为 true 时,局部变量“k”在求值上述表达式后才被明确赋值,而在表达式为 false 时则不然。如果“a”为 false,则对“k”的赋值未正确执行或评估。 让我们考虑语句“X 完成其功能通常时,V 在 X 之后被明确赋值”,“V”是局部变量,“X”是表达式或语句。该语句表示“V”在“X”之后被明确赋值,如果“X”通常完成。假设“X”以错误的方式完成,并且已定义了需要考虑的规则。 上述表达式的不同情况是“V 在 break 之后被明确赋值”,这始终为 true,因为我们知道 break 语句通常不会完成。确实,“V”没有为 break 语句赋值,该语句通常会完成它们。
缩略语“iff”用作“当且仅当”以缩短规则。我们也可以使用另一个缩略语,例如,如果一个规则可能包含一个或多个“未赋值”的出现,那么它执行两个规则
让我们举个例子。
上述陈述可以通过下面的两个规则来理解
明确赋值和表达式布尔常量表达式
以上所有等同于说,“V”在“e”之后未赋值或已赋值,当且仅当“V”在“e”之前未赋值或已赋值。 这是因为常量表达式的值为 true 且从不为 false,而常量表达式的值为 false 且从不为 true,并且满足上述两个规则。 条件与运算符(&&)
条件或运算符(||)
逻辑非运算符(!)
条件运算符(?:)让我们假设 b 和 c 是布尔值表达式。
布尔类型表达式让我们假设“e”是一个布尔类型的表达式,而不是逻辑非表达式,也不是布尔常量表达式 ! a,不是条件与表达式 a&&b,不是条件或表达式 a||b,也不是条件表达式 a ? b:c。
赋值表达式让我们考虑赋值表达式 a=b, a+=b, a%=b, a|=b, a^=b, a*=b, a-=b, a>>=b, a<<=b 等等。
注意:如果 a 是“V”并且在复合赋值如 a&=b 之前“V”没有被明确赋值,那么将发生编译时错误,并且上面讨论的第一个明确赋值规则将包括析取“a is V”,并且对于复合赋值表达式,它不像简单赋值那样,因此“V”在该代码点之后被明确赋值。当我们包含析取“a is V”时,它不会影响确保程序可接受或导致编译时错误的二元决策。它会影响代码中有多少个不同的点被视为错误,因此在实践中,它将提高错误报告的质量。因此,对第一个明确未赋值规则中包含合取“a is V”的类似评论也适用,如上所述。 运算符 ++ 和 --
其他表达式让我们假设表达式不是布尔常量表达式,也不是前缀增量表达式 ++a,不是前缀减量表达式 --a,不是后缀增量 a++,不是后缀减量表达式 a--,不是逻辑非表达式 ! a,不是条件与表达式 a&&b,不是条件或表达式 a||b,不是条件表达式 a? b:c,不是赋值表达式,也不是 lambda 表达式,那么我们必须遵循以下规则 规则 1:如果表达式没有子表达式,则“V”在该表达式之后未赋值或已赋值,当且仅当“V”在该表达式之前未赋值或已赋值。 在这种情况下,它适用于字面量、名称、this(限定和非限定)、没有参数的非限定类实例创建表达式、具有不包含表达式的初始化程序的数组创建表达式、超类字段访问表达式、没有参数的非限定和类型限定方法调用表达式、没有参数的超类方法调用表达式,以及超类和类型限定方法引用表达式。 规则 2:如果表达式有子表达式,“V”在该表达式之后未赋值或已赋值,当且仅当“V”在其最右侧的直接子表达式之后未赋值或已赋值。 有一个微妙的推理过程可以得出结论,即变量“V”可以在方法调用表达式之后被确认为明确未赋值。它将被单独对待,不做任何限定;这种断言并不总是正确的,因为被调用的方法会执行赋值。必须记住,对于 Java 编程语言,明确赋值的概念仅适用于 final 空白变量。 如果“V”是一个空白的 final 局部变量,那么只有声明其所属的方法才会对“V”执行赋值。如果“V”是一个 final 空白字段,那么只有包含“V”声明的类的构造函数或初始化程序才能对“V”执行赋值。最后,显式构造函数调用被特殊处理,即使它们在语法上与包含方法调用的表达式相同。它们不是表达式语句,最后,本节中的规则不适用于显式构造函数调用。 假设一个表达式是 lambda 表达式,并且将应用以下规则
没有规则规定“V”在 lambda 主体之前被明确未赋值。在 lambda 主体之前被明确未赋值的变量将在之后被赋值。因此,我们无法检查变量在执行主体时是否应被赋值。 对于表达式“x”的任何直接子表达式“y”(其中“x”不是 lambda 表达式),“V”在“y”之前未赋值或已赋值,当且仅当以下任一条件成立。
带标签的语句
表达式语句
if 语句对于语句 if (e) S,有以下规则适用:
对于语句 if (e) S else T,有以下规则适用:
Assert 语句对于语句 assert e1 和语句 assert e1: e2,有以下规则适用。
对于语句 assert e1: e2,有一个规则适用:
Switch 语句当且仅当以下所有语句都为 true 时,“V”在 switch 语句之后被赋值或未赋值
下一个主题Java 中的强制类型转换运算符 |
在 Java 中,溢出可以定义为对数值数据类型执行的算术运算的结果超出了该特定数据类型的范围的情况。Java 支持各种数值数据类型,它们是整数类型……
阅读9分钟
目前,Java 被许多科技巨头广泛使用。科技巨头定期聘请 Java 开发人员以满足市场需求。作为回报,公司提供丰厚的薪资待遇和诱人的福利。在本节中,我们将讨论角色...
阅读 6 分钟
在 Java 中,默认参数是一项强大的功能,它允许开发人员为方法参数定义默认值。当一个方法有大量参数,但其中一些参数并非总是必需时,这将非常有用。默认参数已在 Java 8 中引入,并且……
阅读 4 分钟
在数学和计算机科学领域的许多应用程序和方法中,直线都很重要。在给定的 2D 坐标集中找到尽可能多的点可以构成一条直线是一个典型的问题。这个问题应用包括机器学习、计算机...
5 分钟阅读
并发是现代软件开发中的一个基本概念,它允许程序同时执行多个任务。Java 是最流行的编程语言之一,为并发编程提供了强大的支持。近年来,结构化并发已成为在...中编写并发代码的一种强大范例。
阅读 6 分钟
在本文中,我们将学习 Java 编程语言中的开放式哈希和封闭式哈希。在文章结束时,我们将涵盖该主题的不同部分,例如为什么这些技术在 Java 编程语言中使用,它们是什么...
阅读 22 分钟
排列可以定义为,将给定集合的所有成员排列成序列的过程。排列系数用 P(n, r) 表示。它给出从 n 个元素中取 r 个元素的排列数。因此,如果我们有...
阅读 8 分钟
为了将提供的字符读取到 CharBuffer 实例中,使用了 Java 的 Reader Class 的 read(CharBuffer) 方法。Java 可以获取一个称为 CharBuffer 的自定义缓冲区。nio 包,旨在高效地存储和操作字符序列。这种方法使得管理字符...
5 分钟阅读
Java.util.function 包在 Java 8 中首次发布,它包含了 DoubleConsumer 接口,用于在 Java 中进行函数式编程。它是一个接受单个 double 值参数但没有任何输出的函数的示例。为了定义其 accept()...
阅读 4 分钟
在 Java 中,日志记录是一项重要的功能,可帮助开发人员跟踪错误。Java 是一种带有日志记录方法的编程语言。它提供了 Java 1.4 版本中引入的日志记录 API。它提供了捕获日志的能力...
阅读 8 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India