前言

在开发中,常常会碰到检查JAVA对象是不是指定类型的情况,在JAVA中提供了以下几种方法实现此类需求:

  1. instanceOf
  2. Class.isInstance()
  3. Class.isAssignbleFrom()

今天对此三种实现进行具体学习,以加深理解并更好的使用

准备工作

先创建一个名为 Shape 的接口,一个实现了 Shape 接口的类 Triangle , 再定义一个继承 Triangle 类的类 IsoscelesTriangle

1
2
3
4
5
6
7
8
public interface Shape {
}

public class Triangle implements Shape {
}

public class IsoscelesTriangle extends Triangle {
}

以上三个类的类图关系如下

instanceOf

instanceOf 是JAVA中的一个关键字,用于判断 实例对象是否是指定类型的子类型 ,常用于类型转换(cast)之前进行判断,操作的元素是一个对象和一个类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Shape shape = new Triangle();
Triangle triangle = new Triangle();

IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle();
Shape nonspecificShape = null;

assertTrue(shape instanceof Shape);
assertTrue(triangle instanceof Shape);
assertTrue(isoscelesTriangle instanceof Shape);
assertFalse(nonspecificShape instanceof Shape);

assertTrue(shape instanceof Triangle);
assertTrue(triangle instanceof Triangle);
assertTrue(isoscelesTriangle instanceof Triangle);
assertFalse(nonspecificShape instanceof Triangle);

assertFalse(shape instanceof IsoscelesTriangle);
assertFalse(triangle instanceof IsoscelesTriangle);
assertTrue(isoscelesTriangle instanceof IsoscelesTriangle);
assertFalse(nonspecificShape instanceof IsoscelesTriangle);

上面例子测试 instanceOf 左侧对象是否是右侧类型的实例类型

Class.isInstance()

Class.isInstanceinstanceOf 关键字实现的动态版本,从JAVA1.1开始提供,用于判断参数对象是否可以成功的转换成指定的引用类型(左侧的实例类型),操作元素的是一个类型和一个对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
Shape shape = new Triangle();
Triangle triangle = new Triangle();
IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle();
Triangle isoscelesTriangle2 = new IsoscelesTriangle();

Shape nonspecificShape = null;

assertTrue(Shape.class.isInstance(shape));
assertTrue(Shape.class.isInstance(triangle));
assertTrue(Shape.class.isInstance(isoscelesTriangle));
assertTrue(Shape.class.isInstance(isoscelesTriangle2));
assertFalse(Shape.class.isInstance(nonspecificShape)); //参数为null返回false

assertTrue(Triangle.class.isInstance(shape));
assertTrue(Triangle.class.isInstance(triangle));
assertTrue(Triangle.class.isInstance(isoscelesTriangle));
assertTrue(Triangle.class.isInstance(isoscelesTriangle2));

assertFalse(IsoscelesTriangle.class.isInstance(shape));
assertFalse(IsoscelesTriangle.class.isInstance(triangle));
assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle));
assertTrue(IsoscelesTriangle.class.isInstance(isoscelesTriangle2));

如上所示,参数为 null 时结果返回为false

Class.isAssignableFrom

Class.isAssignableOf 用于判断左侧的类型是否与右侧类型相同或是右侧类型的超类或右侧类实现的接口,操作元素为两个类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Shape shape = new Triangle();
Triangle triangle = new Triangle();
IsoscelesTriangle isoscelesTriangle = new IsoscelesTriangle();
Triangle isoscelesTriangle2 = new IsoscelesTriangle();

assertFalse(shape.getClass().isAssignableFrom(Shape.class)); //接口类型是不可以被assign的
assertTrue(shape.getClass().isAssignableFrom(shape.getClass()));
assertTrue(shape.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(shape.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(shape.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));

assertFalse(triangle.getClass().isAssignableFrom(Shape.class)); //接口类型是不可以被assign的
assertTrue(triangle.getClass().isAssignableFrom(shape.getClass()));
assertTrue(triangle.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(triangle.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(triangle.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));

assertFalse(isoscelesTriangle.getClass().isAssignableFrom(Shape.class)); //接口类型是不可以被assign的
assertFalse(isoscelesTriangle.getClass().isAssignableFrom(shape.getClass()));
assertFalse(isoscelesTriangle.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(isoscelesTriangle.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(isoscelesTriangle.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));

assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(Shape.class)); //接口类型是不可以被assign的
assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(shape.getClass()));
assertFalse(isoscelesTriangle2.getClass().isAssignableFrom(triangle.getClass()));
assertTrue(isoscelesTriangle2.getClass().isAssignableFrom(isoscelesTriangle.getClass()));
assertTrue(isoscelesTriangle2.getClass().isAssignableFrom(isoscelesTriangle2.getClass()));

三者的比较

操作类型

  1. instanceOfClass.isInstance() 是一个对象和一个类型进行比较
  2. Class.isAssignableFrom() 是对两个类型进行比较

使用方式

1
2
3
assertFalse(null instanceof Shape);
assertFalse(Shape.class.isInstance(null));
assertFalse(Shape.class.isAssignableFrom(null)); // NullPointerException
  1. instanceOfClass.isInstance() 支持与 null 进行比较
  2. Class.isAssignableFrom() 参数不可以为 null ,如果为 null 则抛出 NullPointerException

字节码

  1. instanceOf 使用的是字节码 instanceof
  2. Class.isInstance()Class.isAssignableFrom() 都是动态方式,它们使用的字节码为 invokeVirtual

适用场景

  1. instanceOf 最常使用的一种,一般是在类型在编译时已经确定的情况下使用
  2. Class.isInstance() 在目标类型在编译时不能确定的情况下使用
  3. Class.isAssignableFrom() 在运行时且只知道类型时使用

总结

以上就是JAVA中常使用的进行类型比较的操作方式,以后再看到类似的使用就不慌了

REF

Class.isInstance vs Class.isAssignableFrom and instanceof | Baeldung