类强制转换异常java

时间:2011-05-02 06:27:48

标签: java

interface Foo { 

}
class Beta implements Foo { 

}
public class Main extends Beta{
    public static void main(String[] args) {
        Beta x = new Beta();
        Foo f= (Main)x;
        }
}

输出java.lang.ClassCastException。 请问xplain为什么会这样?

7 个答案:

答案 0 :(得分:10)

这是因为Main是Beta的子类。因此,如果您有Beta(x变量)的实例,则无法将其强制转换为Main。您可以反过来进行转换:如果您有Main的实例,则可以将其转换为Beta,因为Main包含Beta的所有方法。

答案 1 :(得分:7)

稍作修改,您的代码就可以运行:

interface Foo { 

}
class Beta implements Foo { 

}
public class Main extends Beta{
    public static void main(String[] args) {
        Beta x = new Beta();
        Foo f = x; // Cast to main removed --> works
        }
}

但是这个使代码工作的改变显然不足以彻底理解为什么原始代码不起作用,所以我将尝试解释一下继承逻辑以及在java中使用强制转换: / p>

首先,您的代码可以使用以下继承/实现“图表”来描述:

Foo
 ^
 | (implements)
Beta
 ^
 |  extends
Main

鉴于这些关系,以下陈述是正确的:

  • 可以将 Beta 的实例分配给(接口)类型的变量 Foo

  • 可以分配 Main 的实例 到(类)类型 Beta 或a的变量 (接口)类型的变量 Foo

而且......就是这样。所以以下陈述不正确:

  • Beta 的实例可以分配给(类)类型的变量 Main

仅仅因为类 Beta 不知道类 Main 的存在,因为Beta在继承层次结构中是较高的:这是OO编程中的一般继承契约。

因此你ClassCastException.

尝试使用instanceof运算符和boolean isAssignableFrom(Class<?> cls)类实例方法(如下所示:)

interface Foo {

}

class Beta implements Foo {

}

public class Main extends Beta {
  public static void main(String[] args) {

    // Let's create some instances of Main and Beta :
    Beta b = new Beta();
    Main m = new Main();

    // Let's test those newly created instances :
    System.out.println("is m an instance of Foo ? : " + (m instanceof Foo)); // output true
    System.out.println("is b an instance of Foo ? : " + (b instanceof Foo)); // output true
    System.out.println("is m an instance of Beta ? : " + (m instanceof Beta)); // output true
    System.out.println("is b an instance of Beta ? : " + (b instanceof Beta)); // output true (obviously !)
    System.out.println("is m an instance of Main ? : " + (m instanceof Main)); // output true (obviously !)
    System.out.println("is b an instance of Main ? : " + (b instanceof Main)); // output FALSE !

    // Explanations with the isAssignableFrom() method :
    // Obvious !
    System.out.println("is a variable of type Foo assignable a from a Foo instance ? : "
        + Foo.class.isAssignableFrom(Foo.class)); // output true
    System.out.println("is a variable of type Main assignable from a Main instance ? : "
        + Main.class.isAssignableFrom(Main.class)); // output true
    System.out.println("is a variable of type Beta assignable from a Beta instance ? : "
        + Beta.class.isAssignableFrom(Beta.class)); // output true

    // Now the real thing :
    System.out.println("is a variable of type Foo assignable from a Beta instance ? : "
        + Foo.class.isAssignableFrom(Beta.class)); // output true
    System.out.println("is a variable of type Foo assignable from a Main instance ? : "
        + Foo.class.isAssignableFrom(Main.class)); // output true
    System.out.println("is Main assignable from Beta ? : " + Main.class.isAssignableFrom(Beta.class)); // output false
    System.out.println("is Main assignable from Foo ? : " + Main.class.isAssignableFrom(Foo.class)); // output false
    System.out.println("is Beta assignable from Main ? : " + Beta.class.isAssignableFrom(Main.class)); // output true
    System.out.println("is Beta assignable from Foo ? : " + Beta.class.isAssignableFrom(Foo.class)); // output false

    // Thus the following will work (for example):

    // direct assignation to interface variables (NO CAST is necessary) :
    Foo fb = b;
    Foo fm = m;

    // Some tests :
    System.out.println("is fm an instance of Main ? : " + (fb instanceof Main)); // output true
    System.out.println("is fb an instance of Beta ? : " + (b instanceof Beta)); // output true

    // getting up the hierarchy of main step by step (NO CAST is necessary) :
    Beta bm = m;
    Foo fbm = bm;

    System.out.println("is bm an instance of Main ? : " + (fb instanceof Beta)); // output true
    System.out.println("is fbm an instance of Main ? : " + (b instanceof Main)); // output true

  }
}

那么,为什么你需要使用你必须施放的施法?只有当您知道时,特定的超类型变量才包含特定子类型的实例。让我们在主要方法中添加几行代码来说明这一点:

Object o = m; // m is an instance of Main, but also of java.lang.Object

Foo f2 = (Foo)o; // wont'compile without casting !
Beta b2 = (Beta)o; // wont'compile without casting !
Main m2 = (Main)o;

//And... finally :

Beta b3 = m;

Main m3 = (Main)b3; // won't compile without casting !
// Got it ;) ?

通常更好 - 恕我直言 - 设计你的程序,以便最少减少投射(并在执行此操作之前始终使用instanceofisAssignableFrom()进行检查。)

答案 2 :(得分:1)

与其他人所说的相反,从一个类转换为拥有它的子类是正确的。实际上,这是Java中唯一有效且有用的强制转换用例。 强制转换(T)e在运行时检查将对象视为某种类型T的对象是否有效。在您的程序中,这是无效的,因为x指的是Beta类型的对象,它不是Main类型。

所以这是完全预期的行为。

答案 3 :(得分:0)

因为您无法将Beta转换为Main。 您不能将基类强制转换为派生类。

答案 4 :(得分:0)

正如Darin所说,你不能将超类的对象强制转换为子类。我认为你真正想要做的是:Foo f= x;(因为Beta实现了Foo,所以根本不需要演员表。)

答案 5 :(得分:0)

您无法将基类强制转换为派生类。如果您想使用主要类类型生成 Foo 实例,可以使用如下所示:

interface Foo { }
class Beta implements Foo { }

public class Main extends Beta {

    public static void main (String[] args) {
         Foo x = new Main(); 
    }
}

答案 6 :(得分:0)

只有当要转换的对象实际上是此子类上的实例时,才能将对象转换为子类。

所以,如果你有这样的事情:

Beta x = new Main();

然后上面的转换将起作用,因为“new Main()”将为您提供Main的实例。