1、简介 {#1简介}
Java 中的转换("Cast")是一个基本概念,它允许将一种数据类型转换为另一种数据类型。它是在程序中有效操作对象和变量的关键过程。在现实世界中,"Cast" 类似于将一种单位的度量值转换为另一种单位的度量值,例如将英寸转换为厘米。
在 Java 的多态(Polymorphism)中,当超类引用子类的对象时,经常会使用到转换。例如,我们需要访问子类的特定方法或属性,就需要依靠转换来实现。这一点非常重要,因为 Java 是一种强类型语言,变量具有特定的数据类型。
本文将带你了解 Java Class.cast()
方法和 Cast(强转)操作符两个选项用法和差别,以及每个选项的最佳实践。
2、定义用例 {#2定义用例}
以一个视频游戏角色的层次结构为例。
创建一个包含了超类 Character
(角色)和子类 Warrior
(战士)、Commander
(指挥官)的示例。
该用例涉及创建 Warrior
和 Commander
的实例。这些实例存储在 Character
对象类型的集合中。之后,它们会被检索并转换回各自的特定类型。这种转换允许调用特定子类的方法。
3、定义 Model 类 {#3定义-model-类}
首先,定义第一个继承自 Character
的子类,即实现了 obeyCommand()
方法的 Warrior
:
public class Warrior extends Character {
public void obeyCommand(String command) {
logger.info("Warrior {} obeys a command {}", this.getName(), command);
}
}
然后,创建 Character
的第二个子类,即 Commander
。这个子类实现了一个 issueCommand()
方法,可以向战士们发布命令:
public class Commander extends Character {
public void issueCommand(String command) {
log.info("Commander {} issues a command {}: ", this.getName(), command);
}
}
4、Cast(转换)操作符 {#4cast转换操作符}
在 Java 中,转换(cast )操作符是将一种对象类型转换为另一种对象类型的直接选择。我们使用括号来指定目标类型。
为了演示这一点,让我们编写一个新类 PlayGame
,创建几个角色(每种类型一个)。然后,它会根据角色是 Warrior
还 Commander
,尝试执行命令或发出随机命令。
首先,在 PlayGame
中创建一些角色:
public class PlayGame {
public List<Character> buildCharacters() {
List<Character> characters = new ArrayList<>();
characters.add(new Commander("Odin"));
characters.add(new Warrior("Thor"));
return characters;
}
}
现在,我们要添加根据每个角色进行游戏的功能。根据角色的不同,要么执行给定的命令,要么发出新的命令。
使用转换(cast )操作符:
public void playViaCastOperator(List<Character> characters, String command) {
for (Character character : characters) {
if (character instanceof Warrior) {
// 转换为 Warrior
Warrior warrior = (Warrior) character;
warrior.obeyCommand(command);
}
else if (character instanceof Commander) {
// 转换为 Commander
Commander commander = (Commander) character;
commander.issueCommand(command);
}
}
}
在上面的代码中,我们使用了一种称为向下转型(downcasting)的方法,这意味着我们将父类的实例限制为派生类。这样可用的操作仅限于派生类的方法。
实现步骤:
- 在
PlayGame
类中,定义了一个方法playViaCastOperator()
,它接收一个Character
列表和一条命令 - 遍历角色列表,并根据角色是
Warrior
还是Commander
执行特定操作。使用instanceof
关键字来确认类型 - 如果角色是
Warrior
,就用 cast 运算符(Warrior)
获得Warrior
实例,并调用其obeyCommand()
方法 - 如果角色是
Commander
,就使用 cast 运算符(Commander)
获得Commander
实例,并调用其issueCommand()
方法
5、Class.cast() 方法 {#5classcast-方法}
来看看如何使用 java.lang.Class.cast()
方法实现同样的效果。
现在,在 PlayGame
类中添加新的 playViaClassCast()
方法:
public void playViaClassCast(List<Character> characters, String command) {
for (Character character : characters) {
if (character instanceof Warrior) {
// 转换为 Warrior
Warrior warrior = Warrior.class.cast(character);
warrior.obeyCommand(command);
} else if (character instanceof Commander) {
// 转换为 Commander
Commander commander = Commander.class.cast(character);
commander.issueCommand(command);
}
}
}
如上,使用 Class.cast()
将 Character
转换为 Warrior
或 Commander
。
6、Class.cast() 与 cast 运算符 {#6classcast-与-cast-运算符}
根据不同的标准来比较这两种方法:
| 标准 | Class.cast() | cast 操作符 |
|---------|---------------------------------------------------------------------------|---------------------------------------------|
| 可读性和简洁性 | 使类型转换清晰明确,尤其是在复杂的或泛型代码中,因为类型安全是个问题 | 用于简单的转换操作,在编译时类型已知,有利于可读性 |
| 类型安全 | 通过显式类型检查,提供更好的类型安全性。这在泛型编程中尤其有用,因为在泛型编程中,类型在运行前是未知的,这就确保了类型安全的转换,避免了类转换问题 | 不提供显式类型检查,如果误用,可能导致 ClassCastException
异常 |
| 性能 | 由于额外的方法调用,会增加少量开销,但这通常是次要的,在复杂的情况下,类型安全更为重要 | 由于是直接转换,因此在性能上略有优势,但在大多数实际应用中,这种差异可以忽略不计 |
| 代码可维护性 | 提高复杂或泛型代码的清晰度,使其更易于维护和调试类型问题 | 在简单的场景中更易于使用和理解,使代码维护变得更简单,从而实现直接转换 |
| 灵活性 | 更适合泛型编程或严重依赖反射的框架,确保类型安全和清晰 | 不是泛型编程的最佳选择 |
在进行类型转换之前,我们应该始终通过 instanceof
运算符验证类型,以避免类转换异常。利用库和框架可以更加健壮地处理类型转换和类型检查。
7、总结 {#7总结}
本文介绍了 Java 中的两种类型转换方式,即 Class.cast()
方法和 cast(转换)操作符,并通过实际的相关用例了解了它们的局限性和优势。
使用 cast 操作符可以减少转换过程的冗长。与 Class.cast()
方法相比,它更简洁。不过,这两种方法各有利弊,选择取决于我们的使用情况和实现环境。
Ref:https://www.baeldung.com/java-class-cast-operator-difference