提问人:Flavian Diol D 提问时间:11/9/2023 最后编辑:Flavian Diol D 更新时间:11/15/2023 访问量:251
instanceof Java 中的模式匹配,而不是编译
instanceof Pattern matching in Java, not compiling
问:
以下是摘自《Java - The Complete Reference》一书第 12 版的一段话。
Number myOb = Integer.valueOf(9); int count = 10; if((count < 100) && myOb instanceof Integer iObj) { // is OK // myOb is both an Integer and nonnegative, and count is less than 100. iObj = count; //.. }
编译此片段是因为 if 块仅在 && 的两端都
真。因此,在 if 块中使用 iObj 是有效的。但是,如果出现以下情况,将导致编译错误
您尝试使用 & 而不是 &&,如下所示:
if((count < 100) & myOb instanceof Integer iObj) { // Error!
在这种情况下,编译器无法知道 iObj 是否在 if 块的范围内
因为 & 的右侧不一定会被评估。
我完全不明白最后几行,如果模式匹配失败,为什么代码甚至会进入 if 块,如果它成功并且第一个条件为真,那么使用“&”而不是“&&”有什么问题。
如果我在 if 块中手动初始化 iObj,该代码有效,但为什么模式匹配不这样做?当它的整个想法是创建一个引用变量时,指向上述类型的提取对象。
手动初始化前我得到什么
Compile Error: iObj may not be initialized
我试过了什么
if((count < 100) & myOb instanceof Integer iObj) {
int iObj = (Integer) myOb;
}
现在它起作用了。
我想知道为什么会发生这种情况。
我在 Windows 中使用 JDK 20
java version "20.0.1" 2023-04-18
Java(TM) SE Runtime Environment (build 20.0.1+9-29)
Java HotSpot(TM) 64-Bit Server VM (build 20.0.1+9-29, mixed mode, sharing)
答:
首先,问题中提出的报价是废话!
是“捷径”形式,不保证双方都会被执行;在这种情况下,如果第一项的计算结果为 ,则永远不会触及第二项。 保证对这两个术语进行评估。&&
false
&
然而,由于某种原因,模式匹配可能不适用于单身(但不适用于引文中给出的那个!!&
在 Java 14 中作为预览引入了模式匹配,在 Java 15 中开始了第二个预览,直到在 Java 16 中完成。事实上,JEP 只谈论 和 ,而不是 和 。但是,让它的行为与快捷方式不同是没有多大意义的。instanceof
&&
||
&
|
同时,我尝试了
if( (count < 100) & myOb instanceof Integer iObj )
{
int iObj = (Integer) myOb;
}
使用 Java 21,它出乎意料地有效!但是当我使用 时,它会抱怨正文中的赋值/声明,因为已经声明了......奇怪!!&&
iObj
但是 JLS 6.3.1 也只谈论快捷方式......
也许 JLS 15.22.2 给出了答案:There 和 被标记为“布尔逻辑运算符”,而 6.3.1 则分别将 和 标记为“Conditional-And”或“Conditional-Or”运算符。&
|
&&
||
但随之而来的问题是,为什么术语中与 single 的悬空不会导致语法错误?iObj
instanceof
&
评论
&
&
iObj
iObj
&
&&
instanceof
a instanceof B aB & aB.isValid()
a instanceof B aB
&
aB.isValid()
a instanceof B b
&
a instanceof B b
instanceof
&
&
instanceof
&
instanceof
引文解释为什么第二种情况没有编译的方式措辞非常奇怪,甚至可能是错误的。所以这是我的解释方式。
查看模式匹配变量的方式是,只有在赋值时才会声明它们(在规范中,他们称之为“引入”模式变量)。
让我们看一个例子:
if(myOb instanceof Integer iObj) {
// ...
}
现在在这个 if 语句中,必须返回了 ,所以被“引入”并因此声明。这意味着你既可以从中读取,也可以写入它(因为它不是最终变量,请注意这是有效的 Java)。instanceof
true
iObj
myOb instanceof final Integer iObj
现在让我们跳到给出的第一个案例:
if((count < 100) && myOb instanceof Integer iObj) {
// ...
}
那么为什么会这样呢?语言设计者确保,如果您有以下形式的语句:
if (exprA && exprB) {
// ...
}
它等同于:
if (exprA) {
if (exprB) {
// ...
}
}
这就是为什么你在 Java 和许多其他语言中短路的原因。 对第一种情况这样做,我们得到:
if (count < 100) {
if (myOb instanceof Integer iObj) {
// ...
}
}
因为内部 if 与我给出的第一个示例匹配,所以在 if 块中,模式变量必须被“引入”并且因此是可分配的,这是有道理的。
那么为什么这不能像 一样工作呢?好吧,因为语言设计者决定不这样做。&
&&
关于他们为什么决定这样做,我确实有一个论点。给出这样的语句:
if (exprA & exprB) {
// ...
}
它本质上与以下相同:
boolean tempA = exprA;
boolean tempB = exprB;
if (tempA && tempB) {
// ...
}
虽然我们可以在这里再次拆分运算符,但这并不重要。如果你给,我们会得到.
此语句不能“引入”模式变量,因为它可能不是整数,这意味着它不能保证会被赋值。&&
boolean tempB = myOb instanceof Integer iObj
myOb
iObj
因此,即使 'myOb instanceof Integer iObj' 在这两种情况下都必须返回 true 才能运行 if 块中的代码,因为语言设计者没有像他们那样制定如何引入模式变量的规则,本书中的第 2 种情况不会像第一种情况那样编译。&
&&
那么为什么你可以在if块中使用with而不是with呢?
好吧,正如我们刚才看到的,编译器不认为模式变量被“引入”到块中,所以你可以在里面定义它,但这是非法的,因为模式变量是引入的,这意味着你不能重新声明它。int iObj = ...
&
&&
&
&&
评论
&
&
&&
&
上一个:计算文本文件中模式的所有唯一实例
评论
but why is pattern matching not doing it?
它是为您执行初始化的新语法。如果没有可用或未启用新功能,则无法编译和运行该代码。&