2016-09-23 73 views
0

我決定從Android應用模擬本實施例中的代碼:角色異常錯誤

TextView txt = (TextView) findViewById(R.id.activity_display_message);

findViewById返回View對象,然後我們將它轉​​換爲一個TextView一個(TextViewView子類)

看來我誤解了它是如何工作的。我期待這個代碼的工作,因爲C extends B,因此我應該downcast B對象C

但我在運行時遇到了異常,我無法將B轉換爲C

那麼任何人都可以解釋我錯在哪裏?以及爲什麼Android樣本有效?

public class A{ 
    public static void main(String[] args){ 
     B b = new B(); 
     b.f(); 
     C c = (C)b; 
    } 
} 

class B{ 
    public void f(){ 
     System.out.println("Class B"); 
    } 
} 

class C extends B{ 
    public void f(){ 
     System.out.println("Class C"); 
    } 
} 
+1

如果對象的*執行時間類型*與您嘗試投射到的類型不匹配,則投射將失敗。在你的情況下,它不會,因爲你正在創建一個'B'的實例。在Android情況下,可能涉及的對象實際上是一個「TextView」。請參閱https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html –

+0

研究多態語句,並按照上述註釋 –

回答

2

轉換操作,您可以更改靜態類型的對象,這是另一種說法的「告訴你,瞭解對象的正投的類型是什麼編譯器。」

如果你有B包含C類型的對象類型的變量,你被允許變量轉換爲C

B b = new C(); 
C c = (C)b; // works fine 

這恰恰是允許的,因爲b的對象實際上是一個C

b引用的對象是一個C,編譯器將捕獲你的錯誤,並拋出一個轉換異常:

B b = new B(); 
C c = (C)b; // throws class cast exception 

一個成功和不成功之間的差異是由實際類型決定運行時的對象。有效的代碼管理將View投射到TextView,因爲靜態類型爲View的變量實際上在運行時引用TextView

+0

你是說當'findViewById'正在執行時,它理解所需的視圖是實際上是一個'TextView'並執行類似'return(TextView)the_view_found_by_id'? – CuriousGuy

+1

@CuriousGuy當'LayoutInflater'從xml文件擴充佈局時,它實際上會看到您定義了標籤並實例化了android.widget.TextView類。這就是爲什麼類應該轉換爲xml中定義的同一個類。 –

+0

@AndriiAbramov如果'findViewById'返回一個'TextView'那麼爲什麼我應該像這樣'TextView txt =(TextView)findViewById(R.id)'明確地轉換它? – CuriousGuy

1

在Android中findViewById返回View類的實例。這是TextView和其他視圖元素的直接超類。 所以,如果你想複製這樣的事情,那麼你可以做這樣的事情:

class Test { 

    public static void main(String args[]) { 

     A a = new A(); 
     C c = (C)a.getViewByid('c'); 

     c.f(); 
    } 

} 

class A { 

    public B getViewByid(char c) { 

     B b = null; 
     switch (c) { 

     case 'b': 
      b = new B(); 
      break; 

     case 'c': 
      b = new C(); 
      break; 

     default: 
      b = new B(); 
     } 

     return b; 
    } 
} 

class B { 
    public void f() { 
     System.out.println("Class B"); 
    } 

} 

class C extends B { 
    public void f() {  
     System.out.println("Class C"); 
    } 

} 
2

在java中,你無法分配superclass reference variablesubclass reference variable沒有subclass type的演員。例子可以找到什麼時候需要明確的對象引用強制轉換?當您將超類引用強制轉換爲子類引用時,編譯器很高興,但編譯器並不在意引用的實際對象是什麼。它實際上是否有一個超類對象,或者只是一個持有子類對象的超類引用?編譯時沒有答案,但它必須回答這個問題。

你不能只帶一個父對象,然後突然把它變成一個小孩。父對象不是子類的實例。如果引用的實際對象是超類對象,則將其轉換爲子類引用會導致編譯時錯誤。

在你的情況下B is parent classC is its child

class SuperClass { 
    // ... 
} 

class SubClass extends SuperClass { 
    // ... 
} 

public class Program { 

    public static void main(String[] args) { 

    // case 1: actual SuperClass object 

    SuperClass p1 = new SuperClass(); 

    // case 2: SubClass object is referred by a SuperClass reference 

    SuperClass p2 = new SubClass(); 

    SubClass s1 = (SubClass) p1; //run time error 
    SubClass s2 = (SubClass) p2; //OK 
    } 

}