简体   繁体   English

Java 继承向下转型 ClassCastException

[英]Java inheritance downcast ClassCastException

given the following code, I have a question:鉴于以下代码,我有一个问题:

class A{}
class B extends A {}
class C extends B{}

public class Test {
    public static void main(String[] args) {
        A a = new A();
        A a1=new A();
        B b = new B();
//        a=b;// ok
//        b=(B)a;// ClassCastException
//        a=(A)a1;  // ok
//        a=a1;  // ok

        a=(B)a1;  // compiles ok, ClassCastException
    }
}

My question is with the line in bold.我的问题是粗体线。 My understanding is that for the code to compile, it just needs to be satisfied that the classes are in the same hierarchy and as a result it may work (up the tree implicit casting, down the tree requires explicit casting).我的理解是,对于要编译的代码,只需要满足这些类在同一层次结构中,因此它可以工作(在树上隐式转换,在树下需要显式转换)。 Whenever I have come across ClassCastException it is because the reference was pointing to an object up the tree eg a ref of type B pointing to an object of type A.每当我遇到 ClassCastException 时,都是因为引用指向树上的一个对象,例如 B 类型的 ref 指向 A 类型的对象。

The line in question appears to be a ref of type A pointing to an object of type A. The cast to (B) obviously is what is causing the ClassCastException.有问题的行似乎是类型 A 的引用,指向类型 A 的对象。显然,转换为 (B) 是导致 ClassCastException 的原因。 Can someone explain please what it does to effect this?有人可以解释一下它的作用是什么吗?

Note: If a1 was pointing at an object of type B then it works (just tested it).注意:如果 a1 指向类型为 B 的对象,那么它可以工作(只是对其进行了测试)。 So the downcast is legal regarding the compiler and it can be made to execute without an exception if the reference is pointing at an object of the correct type.因此,向下转换对于编译器是合法的,如果引用指向正确类型的对象,它可以毫无例外地执行。

By casting the A ref a1 to a B and assigning it to a, it appears that the A ref a no longer expects to refer to an object of type A but a B?通过将 A ref a1 强制转换为 B 并将其分配给 a,看来 A ref a 不再期望引用类型 A 而是 B 类型的对象?

Thanks, Sean.谢谢,肖恩。

PS I know this is a bit unusual, preparation for Java certification. PS我知道这有点不寻常,准备Java认证。 Normally we downcast to the type on the left hand side eg b=(B)a;通常我们向下转换到左侧的类型,例如 b=(B)a; (and I can see why this gives a ClassCastException). (我可以理解为什么这会产生 ClassCastException)。

All B's are A's, by inheritance.通过继承,所有 B 都是 A。 But not all A's are B's.但并非所有 A 都是 B。 This particular instance isn't, hence the runtime exception.这个特定的实例不是,因此运行时异常。

You are trying to cast a super class reference variable to a sub class type.您正在尝试将超类引用变量转换为子类类型。 You cannot do this.你不可以做这个。 Think practical, a super class object cannot contain independent methods (other than the super class' methods) of the sub class.考虑实际,超类对象不能包含子类的独立方法(超类的方法除外)。

At run-time you might call a method in the sub class which is certainly not in the super class object .在运行时,您可能会调用子类中的方法,而该方法肯定不在超类object 中

class A{
  public void foo(){}
}
class B extends A {
  public void bar(){}
}

Now,现在,

A a=new A();
B b=(B)a;
b.bar();

When you call like this the compiler, will only check whether the method bar() existed in the class B .当你这样调用编译器时,只会检查方法bar()是否存在于class B That's it.就是这样。 It doesn't care about what is in the 'object' because it is created at runtime.它不关心“对象”中的内容,因为它是在运行时创建的。

But at runtime, as said before there is no bar() method in the object a .但是在运行时,如前所述,对象a没有bar()方法。 b is just a reference that is pointing to object a but a contains only foo() not bar() b只是一个指向对象a的引用,但a只包含foo()而不是bar()

Hope you understood.希望你明白。 Thank you.谢谢你。

Downcasts are illegal.低头是非法的。 An A is not a B and therefore you can't cast it to be one. A 不是 B,因此您不能将其转换为一个。 You can cast B to be A, but not the other way round.您可以将 B 转换为 A,但不能反过来。

In your code example, the variable a is a reference to an object of type A. The class B extends the class B, but the relationship between classes A and B can only be described as follows:在您的代码示例中,变量a是对 A 类型对象的引用。 B 类扩展了 B 类,但 A 类和 B 类之间的关系只能描述如下:

  1. Class B isa Class A (every object of type B can legally be cast to class A). B 类是 A 类(每个 B 类型的对象都可以合法地强制转换为 A 类)。
  2. Class A is-not-a Class B (you can never assign an rvalue of type B to a reference of type A). A 类不是 B 类(您永远不能将 B 类型的右值分配给 A 类型的引用)。

This is legal: a = (A)b;这是合法的: a = (A)b; because class B isa class A.因为B类是A类。

One way to think of it is class B is a superset of class A.一种思考方式是 B 类是 A 类的超集。

If A is a set that contains (1, 2) and B is a set that contains (1, 2, 3) then B is a superset of A (in java terms: B can be cast to A) but A is not a superset of B (A can not be cast to B).如果 A 是包含 (1, 2) 的集合,B 是包含 (1, 2, 3) 的集合,则 B 是 A 的超集(在 Java 术语中:B 可以转换为 A)但 A 不是B 的超集(A 不能转换为 B)。

From a different point of view:从不同的角度:

  • Socrates was mortal.苏格拉底是凡人。
  • All men are mortal.所有的男人都是凡人。

Socrates (class B) isa man (class A).苏格拉底(B 类)是人(A 类)。

This is an invalid minor assertion: All men are Socrates.这是一个无效的小断言:所有人都是苏格拉底。

Remember that legal casts are ruled by the "IS-A" test, why you can compile your code?, because ClassCastException is an Unchecked Exception, since extends from RuntimeException请记住合法强制转换由“IS-A”测试决定,为什么你可以编译你的代码?,因为ClassCastException是一个未经检查的异常,因为从RuntimeException扩展

ClassCastException ---IS-A--> RuntimeException (Another example of a possible legal cast). ClassCastException ---IS-A--> RuntimeException(可能合法转换的另一个示例)。

To downcast in Java, and avoid run-time exceptions, use the following code.要在 Java 中向下转型并避免运行时异常,请使用以下代码。

if (animal instanceof Dog) {
  Dog dogObject = (Dog) animal;
}

Animal is the parent class and Dog is the child class. Animal是父类, Dog是子类。

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

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