Java 中的 Class.cast() 方法和 Cast(转换)操作符

1、简介

Java 中的转换(“Cast”)是一个基本概念,它允许将一种数据类型转换为另一种数据类型。它是在程序中有效操作对象和变量的关键过程。在现实世界中,“Cast” 类似于将一种单位的度量值转换为另一种单位的度量值,例如将英寸转换为厘米。

在 Java 的多态(Polymorphism)中,当超类引用子类的对象时,经常会使用到转换。例如,我们需要访问子类的特定方法或属性,就需要依靠转换来实现。这一点非常重要,因为 Java 是一种强类型语言,变量具有特定的数据类型。

本文将带你了解 Java Class.cast() 方法和 Cast(强转)操作符两个选项用法和差别,以及每个选项的最佳实践。

2、定义用例

以一个视频游戏角色的层次结构为例。

创建一个包含了超类 Character(角色)和子类 Warrior(战士)、Commander(指挥官)的示例。

该用例涉及创建 WarriorCommander 的实例。这些实例存储在 Character 对象类型的集合中。之后,它们会被检索并转换回各自的特定类型。这种转换允许调用特定子类的方法。

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(转换)操作符

在 Java 中,转换(cast )操作符是将一种对象类型转换为另一种对象类型的直接选择。我们使用括号来指定目标类型。

为了演示这一点,让我们编写一个新类 PlayGame,创建几个角色(每种类型一个)。然后,它会根据角色是 WarriorCommander,尝试执行命令或发出随机命令。

首先,在 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() 方法

来看看如何使用 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 转换为 WarriorCommander

6、Class.cast() 与 cast 运算符

根据不同的标准来比较这两种方法:

标准 Class.cast() cast 操作符
可读性和简洁性 使类型转换清晰明确,尤其是在复杂的或泛型代码中,因为类型安全是个问题 用于简单的转换操作,在编译时类型已知,有利于可读性
类型安全 通过显式类型检查,提供更好的类型安全性。这在泛型编程中尤其有用,因为在泛型编程中,类型在运行前是未知的,这就确保了类型安全的转换,避免了类转换问题 不提供显式类型检查,如果误用,可能导致 ClassCastException 异常
性能 由于额外的方法调用,会增加少量开销,但这通常是次要的,在复杂的情况下,类型安全更为重要 由于是直接转换,因此在性能上略有优势,但在大多数实际应用中,这种差异可以忽略不计
代码可维护性 提高复杂或泛型代码的清晰度,使其更易于维护和调试类型问题 在简单的场景中更易于使用和理解,使代码维护变得更简单,从而实现直接转换
灵活性 更适合泛型编程或严重依赖反射的框架,确保类型安全和清晰 不是泛型编程的最佳选择

在进行类型转换之前,我们应该始终通过 instanceof 运算符验证类型,以避免类转换异常。利用库和框架可以更加健壮地处理类型转换和类型检查

7、总结

本文介绍了 Java 中的两种类型转换方式,即 Class.cast() 方法和 cast(转换)操作符,并通过实际的相关用例了解了它们的局限性和优势。

使用 cast 操作符可以减少转换过程的冗长。与 Class.cast() 方法相比,它更简洁。不过,这两种方法各有利弊,选择取决于我们的使用情况和实现环境。


Ref:https://www.baeldung.com/java-class-cast-operator-difference