如何来回转换同一抽象类的两个类


public abstract class Animal {
}
public class Dog implements Animal{
}
public class Cat implements Animal{
}
public static void main(String[] args){
Dog dog = new Dog();
Cat cat = new Cat();
}

如果我有上面的结构,有没有一种方法可以将Cat的实例强制转换为Dog,反之亦然?

否。你误解了演员阵容。它用于三个完全不相关的任务。您可能知道5 + 2是7,但"hey" + "bye""heybye"+运算符用于2完全不相关的任务。强制转换运算符也不例外。

因此,最好为(SomeType) someExpr的实际语法结构保留名称"cast",即很少使用该术语,而是使用3个完全不相关的名称:

图元转换

当parens中的东西是一个基元,特别是一个数字基元:charintlongdoublefloatshortbyte时,就会得到这种"模式"。这就是整个列表-这些类型是用java硬编码的,你不能制作自己的基元,永远不会有比这个1不同的基元类型。

在这种模式下,实际转换发生:

double y = 5.5;
int x = (int) y;

上面的转换这是强制转换运算符的唯一用法

类型断言

当您将非基元类型粘贴在括号中时,就会出现这种模式,并且只适用于具体化部分(非泛型部分,因此不适用于类型的<>部分中的任何内容)。

这是什么,如果一切顺利,什么都没有。它一点作用都没有它无法转换任何东西

具体来说,它将注入以下代码:

  1. 检查表达式是否实际上是括号中类型的实例

2a。如果是,那么什么也不做,但为了解析代码并知道该做什么,表达式(String) whatever的类型是String,即使whatever不是。

2b。如果不是,则当场抛出一个ClassCastException

这就是它所能做的。所以,如果它不抛出一个例外,它什么都不会做。

类型强制/泛型巫毒魔法

为了完整起见,我加入了这一个:在你对java有了很大的了解之前,你永远不应该使用这种特殊的转换模式,而在你对java有了相当多的了解之前这些都是没有意义的。如果这听起来像官样文章,那没关系。忽略它,它并不重要。

对于括号中的非具体化的东西(<>中的东西),它真的真的什么都不做。它不可能抛出任何东西,它实际上可以归结为零字节码。它只是告诉javac停止发牢骚。是你告诉编译器:是的,我知道,你不能保证这些代码中的任何一个都有意义。闭嘴,我知道我在做什么。

示例:

List<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("Test");
List raw = listOfStrings;
List<Integer> numbers = (List<Integer>) raw;

上面的编译(但有警告,因为这是毫无意义的疯狂代码)、运行,甚至没有抛出异常。即使您现在有一个类型为List<Integer>的变量,它包含一个非整数。如果您与此列表交互,即使您甚至没有编写任何类型转换,ClassCastException也会开始发生。

狗和猫

您正在执行第二种模式:类型断言。Dog的实例不是Cat的实例,因此:

Dog dog = new Dog();
Cat c = (Cat) dog;

将失败。事实上,它会因编译时错误而失败,因为编译器知道它永远不会工作。你可以"修复":

Animal a = new Dog();
Cat c = (Cat) a;

现在它将进行编译,但会在第二行抛出ClassCastException。

Animal a = new Dog()到底是什么意思

java中的非基元总是引用。在java中,不可能有一个包含dog的变量。我知道Dog dog = new Dog()看起来确实有一个名为dog的变量,它的值是dog,但事实并非如此。这是对狗的引用。狗太奇怪了,太大了,变量是非常简单的东西。所有变量都像postit注释:它们有固定的、少量的空间。对于intboolean等,数字正好适合postit音符,但对于所有非基元,你不会把狗放在音符上。你在纸条上写下小狗的位置。Dog dog = new Dog()只是的语法糖

Dog dog;   // make a new postit note
new Dog(); // make a dog object
dog = what we just made; // scribble the dog's location on the note

现在Animal a = new Dog()是有意义的:Animal a;Dog dog都只是后置音符。这只是a的位置注释受到限制:它可以是空白的(a = null),也可以保存动物的位置。你可以在上面写下猫、狗、驴或独角兽的位置。但你不能在上面写房子的位置。dog纸条只能放狗的位置(或空白)。

因此,狗的位置可以写在任何一张纸条上。

Cat c = (Cat) animal;

表示:

  • 制作一个新的postit注释,将其命名为c,并对其进行限制,使其只能容纳猫的位置,或者空白
  • 记下一张名为animal的明信片。跟着它,检查它带你去的动物是否真的是猫。如果不是,则抛出一个ClassCastException
  • 但如果是的话,记下那只猫的位置,并在标题为"c"的帖子上乱写

这样做是明智的。

[1] 出于原语转换的目的,被称为Project Valhalla的未来语言更新不太可能改变这一点,尽管它或多或少会引入让您编写自己的原语的概念。

最新更新