1. 简介
在这篇快速教程中,我们将深入探讨 Java 中的 instanceof
操作符。
2. 什么是 instanceof
操作符?
✅ instanceof
是一个二元操作符,用于判断一个对象是否属于某个特定类型。
它的返回值是布尔类型:true
或 false
。由于其主要功能是进行类型比较,因此也被称为 类型比较操作符。
在对未知类型的对象进行 类型转换 前,务必使用 instanceof
进行检查,这样可以有效避免运行时抛出 ClassCastException
异常。
基本语法如下:
(object) instanceof (type)
示例演示:
我们先定义一个类 Round
:
public class Round {
// 实现细节
}
然后定义一个继承自 Round
的类 Ring
:
public class Ring extends Round {
// 实现细节
}
我们可以使用 instanceof
来验证 Ring
实例是否属于 Round
类型:
@Test
void givenWhenInstanceIsCorrect_thenReturnTrue() {
Ring ring = new Ring();
assertTrue(ring instanceof Round);
}
3. instanceof
是如何工作的?
✅ instanceof
的判断依据是“is-a”关系,即基于类的继承关系或接口实现关系。
为了说明这一点,我们创建一个接口 Shape
:
public interface Shape {
// 实现细节
}
再定义一个类 Circle
,它继承 Round
并实现 Shape
接口:
public class Circle extends Round implements Shape {
// 实现细节
}
各种情况下的判断结果:
✅ 对象是该类型的实例:
@Test
void givenWhenObjectIsInstanceOfType_thenReturnTrue() {
Circle circle = new Circle();
assertTrue(circle instanceof Circle);
}
✅ 对象是该类型的子类实例:
@Test
void givenWhenInstanceIsOfSubtype_thenReturnTrue() {
Circle circle = new Circle();
assertTrue(circle instanceof Round);
}
✅ 类型是接口,对象实现了该接口:
@Test
void givenWhenTypeIsInterface_thenReturnTrue() {
Circle circle = new Circle();
assertTrue(circle instanceof Shape);
}
❌ 如果两个类型之间没有任何关系,则不能使用 instanceof
:
我们定义一个类 Triangle
,它也实现了 Shape
,但与 Circle
没有继承关系:
public class Triangle implements Shape {
// 实现细节
}
尝试判断 Circle
是否是 Triangle
类型:
@Test
void givenWhenComparingClassInDiffHierarchy_thenCompilationError() {
Circle circle = new Circle();
assertFalse(circle instanceof Triangle);
}
这会导致编译错误:
java.lang.Error: Unresolved compilation problem:
Incompatible conditional operand types Circle and Triangle
⚠️ 编译器会直接报错,因为两个类型之间没有继承或实现关系。
4. 与 Object
类型一起使用 instanceof
在 Java 中,所有类都隐式继承自 Object
类。因此,**任何对象与 Object
类型进行 instanceof
判断都会返回 true
**。
@Test
void givenWhenTypeIsOfObjectType_thenReturnTrue() {
Thread thread = new Thread();
assertTrue(thread instanceof Object);
}
5. 对 null
使用 instanceof
如果对象为 null
,**instanceof
总是返回 false
。而且,不需要额外做 null
判断**,instanceof
自带空值保护。
@Test
void givenWhenInstanceValueIsNull_thenReturnFalse() {
Circle circle = null;
assertFalse(circle instanceof Round);
}
6. instanceof
与泛型
⚠️ Java 的泛型在运行时会被擦除(Type Erasure),因此不能在泛型类型上直接使用 instanceof
。
例如,以下代码是非法的:
public static <T> void sort(List<T> collection) {
if (collection instanceof List<String>) {
// sort strings differently
}
// omitted
}
编译器会报错:
error: illegal generic type for instanceof
if (collection instanceof List<String>) {
^
✅ 在 Java 中,只有“可具体化类型(reifiable types)”才能用于 instanceof
操作。
可具体化类型是指在运行时保留了完整类型信息的类型。
Java 中的可具体化类型包括:
- 基本类型,如
int
- 非泛型类和接口,如
String
或Random
- 所有类型参数为无界通配符的泛型类型,如
Set<?>
或Map<?, ?>
- 原始类型,如
List
或HashMap
- 由其他可具体化类型组成的数组,如
String[]
、List[]
或Map<?, ?>[]
由于泛型参数本身不是可具体化类型,以下写法是非法的:
public static <T> boolean isOfType(Object input) {
return input instanceof T; // ❌ 编译不通过
}
✅ 但可以使用通配符形式:
if (collection instanceof List<?>) {
// do something
}
7. Stream API 中使用 instanceof
进行类型过滤
Java 8 引入的 Stream API 提供了强大的集合操作能力。在使用 map()
方法进行类型转换时,如果涉及类型转换(casting),建议先使用 instanceof
进行类型检查,避免 ClassCastException
异常。
示例场景:
假设我们有一个 Round
类型的 Stream
:
Stream<Round> roundStream = Stream.of(new Ring(), new Ring(), new Circle());
这个流中包含两个 Ring
和一个 Circle
实例。
如果我们不进行类型检查就直接转换为 Ring
列表:
@Test
void givenWhenStream_whenCastWithoutInstanceOfChk_thenGetException() {
Stream<Round> roundStream = Stream.of(new Ring(), new Ring(), new Circle());
assertThrows(ClassCastException.class, () -> roundStream.map(it -> (Ring) it).collect(Collectors.toList()));
}
就会抛出 ClassCastException
,因为 Circle
不能强制转换为 Ring
。
✅ 正确的做法是先使用 instanceof
过滤:
@Test
void givenWhenStream_whenCastAfterInstanceOfChk_thenGetExpectedResult() {
Stream<Round> roundStream = Stream.of(new Ring(), new Ring(), new Circle());
List<Ring> ringList = roundStream
.filter(it -> it instanceof Ring)
.map(it -> (Ring) it)
.collect(Collectors.toList());
assertEquals(2, ringList.size());
}
8. 总结
本文我们系统介绍了 Java 中的 instanceof
操作符,包括其基本用法、工作原理、与泛型和 Stream API 的结合使用等内容。
完整示例代码可参考:GitHub 项目地址 ✅