拨开荷叶行,寻梦已然成。仙女莲花里,翩翩白鹭情。
IMG-LOGO
主页 文章列表 Java中ClassCastException的说明

Java中ClassCastException的说明

白鹭 - 2021-11-24 851 0 0

1.概述

在这个简短的教程中,我们将集中讨论ClassCastException ,这是一个常见的Java异常。

ClassCastException是未经检查的异常,它指示代码已尝试将引用转换为不是子类型的类型

让我们看一下导致引发此异常的一些情况,以及如何避免它们。

2.显式投射

对于我们的下一个实验,让我们考虑以下类:

public interface Animal {

 String getName();

 }
public class Mammal implements Animal {

 @Override

 public String getName() {

 return "Mammal";

 }

 }
public class Amphibian implements Animal {

 @Override

 public String getName() {

 return "Amphibian";

 }

 }
public class Frog extends Amphibian {

 @Override

 public String getName() {

 return super.getName() + ": Frog";

 }

 }

2.1。选修课

ClassCastException的最常见情况是显式转换为不兼容的类型。

例如,让我们尝试将Frog放到Mammal

Frog frog = new Frog();

 Mammal mammal = (Mammal) frog;

我们可能会在ClassCastException ,但实际上,我们会收到编译错误:“不兼容的类型:无法将Frog转换为Mammal”。但是,当我们使用普通的超类型时,情况就发生了变化:

Animal animal = new Frog();

 Mammal mammal = (Mammal) animal;

现在,我们从第二行ClassCastException

Exception in thread "main" java.lang.ClassCastException: class Frog cannot be cast to class Mammal (Frog and Mammal are in unnamed module of loader 'app')

 at Main.main(Main.java:9)

由于Frog Mammal的子类型, Frog Mammal的检查后向下转换是不兼容的。在这种情况下,编译器无法为我们提供帮助,因为Animal变量可能包含兼容类型的引用。

有趣的是,仅当我们尝试强制转换为明确不兼容的类时,才会发生编译错误。接口并非如此,因为Java支持多个接口继承,但仅支持类的单个继承。因此,编译器无法确定引用类型是否实现特定的接口。让我们举例说明:

Animal animal = new Frog();

 Serializable serial = (Serializable) animal;

我们ClassCastException而不是编译错误:

Exception in thread "main" java.lang.ClassCastException: class Frog cannot be cast to class java.io.Serializable (Frog is in unnamed module of loader 'app'; java.io.Serializable is in module java.base of loader 'bootstrap')

 at Main.main(Main.java:11)

2.2。转换数组

我们已经看到了类如何处理转换,现在让我们看一下数组。数组强制转换与类强制转换相同。但是,我们可能会因自动装箱和键入促销而感到困惑,或者缺少它们。

因此,让我们看看尝试以下转换时原始数组会发生什么:

Object primitives = new int[1];

 Integer[] integers = (Integer[]) primitives;

第二行抛出ClassCastException因为自动装箱不适用于数组。

如何进行类型推广?让我们尝试以下方法:

Object primitives = new int[1];

 long[] longs = (long[]) primitives;

我们还得到了ClassCastException因为类型提升不适用于整个数组。

2.3。安全铸造

在显式转换的情况下,强烈建议在尝试使用instanceof进行转换之前检查类型的兼容性**。**

让我们看一个安全的强制转换示例:

Mammal mammal;

 if (animal instanceof Mammal) {

 mammal = (Mammal) animal;

 } else {

 // handle exceptional case

 }

3.堆污染

按照Java规范:“仅当程序执行某些涉及原始类型的操作,这会引起编译时未经检查的警告时,才会发生堆污染”。

对于我们的实验,让我们考虑以下通用类:

public static class Box<T> {

 private T content;



 public T getContent() {

 return content;

 }



 public void setContent(T content) {

 this.content = content;

 }

 }

现在,我们将尝试如下污染堆:

Box<Long> originalBox = new Box<>();

 Box raw = originalBox;

 raw.setContent(2.5);

 Box<Long> bound = (Box<Long>) raw;

 Long content = bound.getContent();

最后一行将抛出ClassCastException因为它无法将D ouble引用Long

4.通用类型

在Java中使用泛型时,我们必须警惕类型擦除,这在某些情况下ClassCastException

让我们考虑以下通用方法:

public static <T> T convertInstanceOfObject(Object o) {

 try {

 return (T) o;

 } catch (ClassCastException e) {

 return null;

 }

 }

现在让我们称之为:

String shouldBeNull = convertInstanceOfObject(123);

乍一看,我们可以合理地期望catch块返回一个空引用。但是,在运行时,由于类型擦除,参数将强制转换为Object而不是String 。因此,编译器面临将Integer分配给String的任务,这将引发ClassCastException.

5.结论

在本文中,我们研究了一系列不适当转换的常见情况。

不管是隐式还是显式,将Java引用强制转换为另一种类型都可能导致ClassCastException除非目标类型与实际类型相同或其后代

本文中使用的代码可以 在GitHub上找到

标签:

0 评论

发表评论

您的电子邮件地址不会被公开。 必填的字段已做标记 *