将Java子类转换为父类

6

类 Lion 继承自 Animal。

这是我的代码:

Animal a = new Animal();
Lion b = new Lion();
Animal c = (Animal) b;

Animal[] arr = { a, b, c };

for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i].getClass().getName());
    arr[i].run();
}

结果是:

test2.Animal

动物奔跑...

test2.Lion

狮子奔跑...

test2.Lion

狮子奔跑...

从例子中可以看出,"c"被认为是一只"狮子"而不是"动物"。为什么会这样呢?

也许这个问题可以帮助你理解:https://dev59.com/MW855IYBdhLWcg3w_5cQ - NESPowerGlove
这被称为"多态性"。 - Gaskoin
4个回答

11
因为 c 确实是一只狮子。
Lion b = new Lion();   // Creates a Lion
Animal c = (Animal) b; // Refers to the Lion through an Animal variable

现在,c 是一个指向 Lion 对象的 Animal 类型的引用。该对象仍然是一只狮子,只是对它的引用被限制在 Animal 方面。当你询问该对象的类是什么(而不是在 c 变量/数组中的第三个条目中的接口),它会告诉你它是一只 Lion

这就像这种情况:

Map m = new HashMap();

m 变量的类型是 Map,所以你只能使用它来访问 Map 接口定义的内容,但是它所引用的 对象 是一个 HashMap 实例。


你好,能否解释一下即使Lion对象被转换为Animal对象,如何恢复引用Lion对象的方法?在C++中,这会导致Lion中所有不在Animal中的字段被修剪。 - Vallerious
@Vallerious - Java和C++使用的语义相当不同。Java的对象变量是对对象的引用,而不是直接包含对象,因此它们更像C++指针。(警告:我已经22年没有真正做过C++了。) 在上面的例子中,Java的Lion b就像C++的Lion *bb指向对象,而不是直接包含它。因此,在Java中,Animal c = (Animal);就像在C++中的Animal *c = (Animal*)b;,只是将第二个变量指向同一个对象。 - T.J. Crowder
1
@Vallerious - 对于此事,这段Java代码这段C++代码相似(再次说明,我的C++很生疏)。 - T.J. Crowder
谢谢,这解释清楚了。我检查过了,确实在使用 Animal a = lion 时会发生切片操作,我猜赋值运算符不会将字段复制到 Animal 中,因为这是无法实现的。 - Vallerious
1
我的意思是C ++。因此,Java和C ++在这方面相似,只是Java为我们隐藏了指针语法。 :) - Vallerious
显示剩余2条评论

3

强制类型转换并不会改变对象的类型,它只是限制了对象可以调用的方法为父类的方法。由于这些原因,你不能将一个 Banana 转换成 Animal

在你的代码中,进行了类型转换的语句为

Animal c = (Animal) b;

发生的自动化方式。当您进行向下转换时,只需要指定要转换的类型即可:
Animal a = new Dog();
Dog d = (Dog) a;

但是,ad仍然指向堆中的一个Dog对象,因此如果它们覆盖了Animal类的方法,则将使用Dog类的实例方法。换句话说,a是一个Dog,但只要它被声明为(或强制转换为)Animal,它只能使用Animal方法。

2

您正在调用getClass方法。

方法调用在运行时解析,因此它输出Lion而不是Animal


1
你的对象c是一个对象的引用,该对象必须是类型Animal或任何子类。仅因为对象引用是Animal并不保证对象是Animal,它只意味着它将表现为Animal,并且您可以调用您想要的该类中的所有方法。这是多态性的一部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接