开发人员和Java专家概述了Java的最新版本中的instanceof运算符,以及如何使用它来改进您的代码。
根据一些调查(如JetBrains的出色调查),尽管Java 8是2014年发行的,但它目前是使用最多的Java版本。
本文是系列文章中的第一篇,标题为“超越Java 8”,其灵感来自于我的《Java for Aliens》一书的内容。这些文章将引导读者逐步探索从Java 9引入的最重要的功能。其目的是使读者了解从Java 8向前迈进的重要性,并说明最新的Java带来的巨大优势。语言版本。
在本文中,我们将看看Java 14中作为预览功能引入的一个有趣的新颖性(请参阅相关文章)。这是称为模式匹配的复杂功能的第一部分。尽管将来,它将影响将来的各种编程结构,但是模式匹配仅可与instanceof操作员一起用作功能预览。这将从根本上改变我们使用此运算符的方式。
instanceof与比较运算符一样,二进制运算符将返回布尔值。该运算符的独特之处在于它使用引用作为第一个操作数,并使用复杂类型作为第二个操作数。true如果在运行时引用(定义第一个操作数)指向由类型(定义第二个操作数)实例化的对象,则返回。true即使引用指向由第二个操作数指定的类型的子类实例化的对象,它也会返回。如果不满足这两个条件之一,则instanceof操作员返回false。
假设我们要创建一个确定公司员工薪水的系统,并考虑以下类别:
假设我们必须向所有类型的员工支付薪水,我们可以开始将公司的所有员工归为一个异构集合:
要管理员工工资,我们可以创建以下方法:
这使instanceof操作员可以测试多态参数emp所指向的类型并相应地设置薪水。
现在,我们可以在一个foreach循环(具有180次迭代)中调用此方法,传递异构集合的所有元素,从而达到我们的目标:
在前面的示例中,我们观察到instanceof操作员允许我们测试参考点指向哪种类型的实例。但是,我们已经知道,指向由子类实例化的对象的超类引用无法访问在子类中声明的成员。例如,假设程序员的薪水取决于经验的年限。在这种情况下,测试引用是否emp指向Programmer实例后,我们将需要访问yearsOfExperience变量。如果我们尝试使用以下语法访问它:我们会得到一个编译时错误:
事实上,参考emp,作为的Employee类型,将无法访问在子类中声明的方法。为了克服这个障碍,我们可以使用对象投射机制。在实践中,我们必须声明一个Programmer类型引用,并使其指向引用所指向的内存地址,并emp使用强制转换来确认指向范围。这种Programmer类型的新引用将使我们能够访问Programmer实例的任何成员。
对象的转换使用非常类似于原始数据之间的转换的语法:
注意,我们现在可以访问封装的变量yearsOfExperience。
在图1中,我们理想地用图形表示来概述情况,其中对象由Employee类型emp引用和Programmer 类型pro引用指向。
在图1中,两个引用指向相同的对象,但是指向范围不同。仅在与instanceof操作员一起检查对象的有效性之后,才必须使用对象强制转换。实际上,编译器无法确定某个对象是否位于某个地址而不是另一个地址。只有在运行时,Java虚拟机才能使用instanceof操作员解决任何疑问。
instanceof不能将运算符和对象强制转换的组合使用定义为Java最佳实践,但它无疑是一种众所周知且广泛使用的编程模式。然而,显而易见的是,这种做法无疑是冗长的。它也是重复的;在前面的示例中,我们Programmer在两行中对类型进行了三次命名。最后,在使用进行测试之后instanceof,显然假定下一条语句为强制转换。实际上,某些IDE允许我们自动执行此操作。但是,如果我们不使用IDE自动执行编码,则如果此代码重复多次,则可能最终会进行大量复制粘贴操作,这也可能意味着ClassCastException在运行时出现了。
Java 14引入了复杂功能的第一部分,即模式匹配 作为功能预览。在此功能中,模式(请勿与设计模式混淆)由以下部分组成:
因此,模式被定义为表达复杂解决方案的一种综合方式。
完全实现此功能后,还将影响其他主题,例如record类型和switch构造。在版本15中,模式匹配仍作为功能预览呈现,而实现的唯一部分涉及模式,该模式涉及instanceof我们刚刚看到的操作员和对象强制转换。实际上,通过启用功能预览,我们可以使用其他语法:
该语法在操作旁边指定Programmer-type引用。该引用可以立即使用,并且不需要强制转换,因为它已经是-type引用。因此,语法非常简单,但必须注意一些问题。 proinstanceofProgrammer
特别地,pro引用被定义为绑定变量。绑定变量是特定的局部变量,具有取决于模式的新型约束范围。像局部变量一样,它可以与具有相同标识符的实例变量共存。不同之处在于,其范围取决于谓词的结果,即instanceof测试的结果是否为true或false。在前面的示例中,该pro引用仅在与该if构造有关的代码块中可见。如果我们添加了该else子句,并以instanceof以下方式为测试添加了NOT运算符前缀:
那么该pro引用将仅在else子句的代码块中可见,而在代码块中不可见if。
同样,绑定变量是隐式的final,并且其寻址无法更改。例如,以下
会导致以下编译时错误:
当前,这是Java 15中绑定变量的行为,其中模式匹配instanceof仍然是功能预览。但是在2021年3月发布的版本16中,其模式匹配instanceof将被正式化为标准Java功能,并且该限制应永久删除。
无论如何,通过绑定变量(因为它是引用),仍然可以更改其指向的对象的内部状态。例如,以下代码有效:
实际上,没有将新地址分配给pro引用,而是仅在其上调用方法。
目前,instanceof尚未完全定义模式匹配的最终演变,并且可以进行其他更改。当我们有机会测试此功能的标准版本时,我们将回来更新本文。
在本文中,我们了解了Java 14如何引入模式匹配instanceof作为功能预览。这项新功能为绑定变量引入了一种新的作用域,它将永远改变我们使用instanceof运算符和对象强制转换的方式。在Java 15中,此功能仍处于预览状态,但是在版本16中,由于收到了用户的反馈,因此将会有所变化。
instanceof因此,的模式匹配代表该语言的又一小步。
即使忽略了最新版本的JDK提供的增强的安全性,也有很多理由来升级您的Java知识,或者至少升级您自己的Java运行时安装。我的书籍《Java for Aliens》启发了“超越Java 8”系列,它包含了从头开始学习Java所需的所有信息,并使用了经过20年经验完善的,经过测试的教学方法。使学习变得简单而令人兴奋。它的结构还可以加深主题,并具有可以为您的职业带来改变的高级知识。
参考:《2020最新Java基础精讲视频教程和学习路线!》