簡體   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