Java中的ClassCastException和解析

时间:2020-01-09 10:34:58  来源:igfitidea点击:

如果尝试将对象强制转换为非实例类型,则抛出Java中的ClassCastException。

例如,考虑以下代码

Object l = Long.valueOf("120");
System.out.println(l); //120
Number n = (Number)l;
System.out.println(n); // 120

在这里,我们有一个存储在Object类型中的Long值引用。稍后我们将其强制转换为Number,因为Number是Long的超类(Long也是Number类型),因此可以毫无问题地将Long转换为Number。

现在我们对其进行更改,以便将Long值的引用存储在Number类型中。后来我们将其转换为Integer。

Number l = Long.valueOf("120");
System.out.println(l);
Integer i = (Integer)l;
System.out.println(i);

输出:

120
Exception in thread "main" java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer

由于Long不是Integer类型,因此将类型转换为Integer会导致java.lang.ClassCastException。 Long和Integer均为Number类型,但不能在Integer和Long之间进行强制转换。

当我们具有继承性(父子类)并使用运行时多态性(其中超类可以存储对子类的引用)时,在这种情况下,当我们进行类型转换以将一种类型的对象转换为另一类ClassCastException时,将被抛出。这是要理解何时抛出ClassCastException的另一类层次结构。

Class A {
	..
}

class B extends A {
	...
}

class C extends A {
	...	
}

A是B类和C类的父类。使用此层次结构,我们具有以下铸造规则。

  • 我们可以将A,B或者C中的任何一个实例转换为Object,因为Object是Java中所有类的超类。
  • 我们可以将B或者C的实例强制转换为A,因为B和C的类型也均为A。
  • 如果A持有对B类型实例的引用,则可以将其仅强制转换为B而不是C。对于C类型实例也是如此。这样就可以了。
A a = new B();
System.out.println((B)a);

不是这个

System.out.println((C)a);

再次,这没关系

A a = new C();
System.out.println((C)a);

不是这个

System.out.println((B)a);
  • 尽管B和C均为A类型,但它们彼此不兼容,因此无法从B转换为C或者从C转换为B。

Java ClassCastException层次结构

如果为RuntimeException类型,则为ClassCastException,这表示它是未经检查的异常。

Java中ClassCastException的异常层次结构如下:

如何避免ClassCastException

通过使用通用Collections和随后的类型安全,已经避免了ClassCastException的一个主要原因。

避免ClassCastException的另一种方法是在转换对象之前使用instanceof运算符确定对象的兼容性。

class B extends A {
}

class C extends A {
}

public class A {
  public static void main(String[] args) {
    A obj1 = new B();
    A obj2 = new C();
    if(obj2 instanceof B) {
      System.out.println((B)obj2);
    } else {
      System.out.println("Not compatible");
    }
    
    if(obj1 instanceof B) {
      System.out.println((B)obj1);
    } else {
      System.out.println("Not compatible");
    }
  }
}

输出:

Not compatible
Hyman@theitroad