2016-09-23 78 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 
    } 

}