如何来回转换相同抽象 class 的两个 classes
How to cast two classes of the same abstract class back and forth
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,反之亦然?
没有。您误解了 cast 运算符。它用于三个 完全不相关的 任务。您可能知道 5 + 2
是 7,但 "hey" + "bye"
是 "heybye"
。 +
运算符用于 2 个 完全不相关的 任务。 cast 运算符也不例外。
因此,最好为 (SomeType) someExpr
的实际句法结构保留名称 'cast',即很少使用该术语,而是将名称用于您可以做的 3 件完全不相关的事情有了它:
原始转换
当 parens 中的东西是原始数据时,你会得到这个 'mode',具体来说,是数字原始数据:char
、int
、long
、double
、float
、short
或 byte
。这就是整个列表——这些类型在 java 中被硬编码,你不能创建自己的基元,永远不会有与此不同的基元类型 1.
在此模式下,实际发生转换:
double y = 5.5;
int x = (int) y;
上面的转换,这是转换运算符的唯一用法。
类型断言
当您在括号中输入 non-primitive 时会出现此模式,并且仅适用于具体化部分(non-generics 部分,因此 <>
部分中的任何内容均无效类型)。
这是什么意思,如果一切顺利,没有。它根本不做任何事情。 无法转换任何东西。
具体来说,它会注入如下代码:
- 检查表达式是否实际上是括号中类型的实例。
2a。如果是,那么什么也不做,但是为了解析代码并知道要做什么,表达式 (String) whatever
是字符串类型,即使 whatever
不是。
2b。如果不是,那就当场扔一个ClassCastException
。
这就是它所能做的。所以,如果它没有抛出异常,它什么都不做。
类型强制/泛型巫毒魔法
为了完整起见,我将这个包括在内:你不应该使用这种特定的施法模式,直到你在 java 和 none 中更先进在您对 java 了解相当多之前,它甚至是有意义的。如果这对您来说听起来像是官话,那很好。无视就好,不重要
对于 non-reified 括号中的内容(<>
中的内容),它确实确实 完全没有作用 。它不可能抛出任何东西,它实际上归结为零字节码。它只是告诉 javac
停止抱怨。是你告诉编译器:是的,我知道,你不能保证这些代码中的任何一个都有意义。闭嘴,我知道我在做什么
示例:
List<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("Test");
List raw = listOfStrings;
List<Integer> numbers = (List<Integer>) raw;
以上编译(但有警告,因为这是毫无意义的疯狂代码),并运行,甚至没有抛出异常。即使您现在有一个 List<Integer>
类型的变量,其中包含一个 not-integer。如果您与此列表交互,ClassCastExceptions 将开始出现,即使您甚至没有编写任何转换。
狗和猫
您正在执行第二种模式:类型断言。 Dog 的实例不是 Cat 的实例,因此:
Dog dog = new Dog();
Cat c = (Cat) dog;
会失败。它实际上会因 compile-time 错误而失败,因为编译器知道它永远不会工作。您可以'fix':
Animal a = new Dog();
Cat c = (Cat) a;
现在可以编译了,但是会在第二行抛出 ClassCastException。
Animal a = new Dog()
是什么意思?
java 中的 Non-primitives 是 always 引用。在 java 中不可能有一个包含狗的变量。我知道 Dog dog = new Dog()
确实看起来你有一个名为 dog
的变量,它的值是一只狗,但是,它不是。它是 对狗的引用 。狗太奇怪了,太大了,变量是非常简单的东西。所有变量都像便利贴:它们有一个固定的、少量的 space。对于 int
和 boolean
等,数字刚好在便利贴上,但对于所有 non-primitive,您不会将狗字面意思放在便条上。你在纸条上写狗的位置。 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
note 只能写狗的位置(或者留空)
因此,狗的位置可以写在任何一张纸条上。
Cat c = (Cat) animal;
表示:
- 新建一张便利贴,命名为
c
,限制为只能写猫的位置,否则为空白。
- 记下名为
animal
的便利贴。跟随它并检查它带你去的动物是否真的是一只猫。如果不是,则抛出一个ClassCastException
.
- 但如果是,请记下那只猫的位置并将其写在标题为 'c' 的帖子上。
这是明智之举。
[1] 出于原语转换的目的,被称为 Project Valhalla 的未来语言更新不太可能改变这一点,尽管它或多或少会引入让您编写自己的原语的概念。
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,反之亦然?
没有。您误解了 cast 运算符。它用于三个 完全不相关的 任务。您可能知道 5 + 2
是 7,但 "hey" + "bye"
是 "heybye"
。 +
运算符用于 2 个 完全不相关的 任务。 cast 运算符也不例外。
因此,最好为 (SomeType) someExpr
的实际句法结构保留名称 'cast',即很少使用该术语,而是将名称用于您可以做的 3 件完全不相关的事情有了它:
原始转换
当 parens 中的东西是原始数据时,你会得到这个 'mode',具体来说,是数字原始数据:char
、int
、long
、double
、float
、short
或 byte
。这就是整个列表——这些类型在 java 中被硬编码,你不能创建自己的基元,永远不会有与此不同的基元类型 1.
在此模式下,实际发生转换:
double y = 5.5;
int x = (int) y;
上面的转换,这是转换运算符的唯一用法。
类型断言
当您在括号中输入 non-primitive 时会出现此模式,并且仅适用于具体化部分(non-generics 部分,因此 <>
部分中的任何内容均无效类型)。
这是什么意思,如果一切顺利,没有。它根本不做任何事情。 无法转换任何东西。
具体来说,它会注入如下代码:
- 检查表达式是否实际上是括号中类型的实例。
2a。如果是,那么什么也不做,但是为了解析代码并知道要做什么,表达式 (String) whatever
是字符串类型,即使 whatever
不是。
2b。如果不是,那就当场扔一个ClassCastException
。
这就是它所能做的。所以,如果它没有抛出异常,它什么都不做。
类型强制/泛型巫毒魔法
为了完整起见,我将这个包括在内:你不应该使用这种特定的施法模式,直到你在 java 和 none 中更先进在您对 java 了解相当多之前,它甚至是有意义的。如果这对您来说听起来像是官话,那很好。无视就好,不重要
对于 non-reified 括号中的内容(<>
中的内容),它确实确实 完全没有作用 。它不可能抛出任何东西,它实际上归结为零字节码。它只是告诉 javac
停止抱怨。是你告诉编译器:是的,我知道,你不能保证这些代码中的任何一个都有意义。闭嘴,我知道我在做什么
示例:
List<String> listOfStrings = new ArrayList<String>();
listOfStrings.add("Test");
List raw = listOfStrings;
List<Integer> numbers = (List<Integer>) raw;
以上编译(但有警告,因为这是毫无意义的疯狂代码),并运行,甚至没有抛出异常。即使您现在有一个 List<Integer>
类型的变量,其中包含一个 not-integer。如果您与此列表交互,ClassCastExceptions 将开始出现,即使您甚至没有编写任何转换。
狗和猫
您正在执行第二种模式:类型断言。 Dog 的实例不是 Cat 的实例,因此:
Dog dog = new Dog();
Cat c = (Cat) dog;
会失败。它实际上会因 compile-time 错误而失败,因为编译器知道它永远不会工作。您可以'fix':
Animal a = new Dog();
Cat c = (Cat) a;
现在可以编译了,但是会在第二行抛出 ClassCastException。
Animal a = new Dog()
是什么意思?
java 中的 Non-primitives 是 always 引用。在 java 中不可能有一个包含狗的变量。我知道 Dog dog = new Dog()
确实看起来你有一个名为 dog
的变量,它的值是一只狗,但是,它不是。它是 对狗的引用 。狗太奇怪了,太大了,变量是非常简单的东西。所有变量都像便利贴:它们有一个固定的、少量的 space。对于 int
和 boolean
等,数字刚好在便利贴上,但对于所有 non-primitive,您不会将狗字面意思放在便条上。你在纸条上写狗的位置。 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
note 只能写狗的位置(或者留空)
因此,狗的位置可以写在任何一张纸条上。
Cat c = (Cat) animal;
表示:
- 新建一张便利贴,命名为
c
,限制为只能写猫的位置,否则为空白。 - 记下名为
animal
的便利贴。跟随它并检查它带你去的动物是否真的是一只猫。如果不是,则抛出一个ClassCastException
. - 但如果是,请记下那只猫的位置并将其写在标题为 'c' 的帖子上。
这是明智之举。
[1] 出于原语转换的目的,被称为 Project Valhalla 的未来语言更新不太可能改变这一点,尽管它或多或少会引入让您编写自己的原语的概念。