繁体   English   中英

class 强制转换异常 java

[英]class cast exception 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;
        }
}

output java.lang.ClassCastException 为什么会这样,请解释一下?

发生这种情况是因为 Main 是 Beta 的子类。 因此,如果您有一个 Beta 实例( x变量),则不能将其转换为 Main。 您可以反过来进行转换:如果您有 Main 的一个实例,您可以将其转换为 Beta,因为 Main 包含 Beta 的所有方法。

稍作改动,您的代码就可以工作:

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
        }
}

但是这种让代码工作的改变显然不足以彻底理解为什么原始代码不能工作,所以我将尝试解释一下 inheritance 的逻辑和 java 中强制转换的使用:

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

Foo
 ^
 | (implements)
Beta
 ^
 |  extends
Main

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

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

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

而且……就是这样。 所以下面的说法是不正确的:

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

Simply because class Beta has no knowledge of the existence of class Main , as Beta is upper in the inheritance hierachy: this is the general inheritance contract in OO programming.

因此你ClassCastException.

尝试使用instanceof运算符和boolean isAssignableFrom(Class<?> cls) Class 实例方法(类似这样:)

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

  }
}

那么,为什么你需要使用强制强制转换呢? 仅当您知道特定的超类型变量包含特定子类型的实例时。 让我们在 main 方法中再添加几行来说明这一点:

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() )。

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

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

只有当被强制转换的 object 实际上是该子类上的实例时,您才能将 object 强制转换为子类。

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

Beta x = new Main();

那么上面的转换就会起作用,因为“new Main()”会给你一个 Main 的实例。

因为您不能将 Beta 转换为 Main。 您不能将基础 class 转换为派生的。

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

您不能将基础 class 转换为派生 class。 如果你想用Main class 类型制作Foo实例,你可以像下面这样使用:

interface Foo { }
class Beta implements Foo { }

public class Main extends Beta {

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM