CodeGym /课程 /Java 核心 /类型转换。拓宽和窄化转换

类型转换。拓宽和窄化转换

Java 核心
第 4 级 , 课程 3
可用

“嗨,阿米戈!今天课程的主题是拓宽和窄化类型转换。你很久以前就学了拓宽和窄化原始类型。第 10 级。今天我们要讲讲它如何用于引用类型,也就是类的实例。”

实际上,这一块相当简单。想象下类的继承链:类、父类、父类的父类等,一直回溯到 Object 类。由于一个类包含它所继承类的所有成员方法,因此这个类的实例可以保存在其类型是任何一个父类类型的变量中

下面是一个示例:

代码 说明
class Animal
{
public void doAnimalActions();
}class Cat extends Animal
{
public void doCatActions();
}class Tiger extends Cat
{
public void doTigerActions();
}
这里有三个类声明:Animal、Cat 和 Tiger。Cat 继承 Animal。Tiger 继承 Cat。
public static void main(String[] args)
{
Tiger tiger = new Tiger();
Cat cat = new Tiger(); Animal animal = new Tiger(); Object obj = new Tiger();
}
Tiger 对象可始终赋给类型是其父类类型的变量。对于 Tiger 类,分别是 Cat、Animal 和 Object。

现在我们来看一下拓宽和窄化转换。

如果赋值操作使我们在继承链中向上移动(靠近 Object 类),那么我们正在处理拓宽转换(也称为向上转换)。如果我们沿着对象类型的链向下移动,那么这就是窄化转换(也称为向下转换)。

沿继承链上移称为拓宽,因为它趋向更为普遍的类型。不过,这样我们就无法调用通过继承添加到该类的方法。

代码 说明
public static void main(String[] args)
{
Object obj = new Tiger();
Animal animal = (Animal) obj; Cat cat = (Cat) obj; Tiger tiger = (Tiger) animal; Tiger tiger2 = (Tiger) cat;
}
窄化类型时,你要使用类型转换运算符,即我们执行显式转换。

这就造成 Java 机器检查对象是否确实继承我们要转换到的类型。

这个小小的创新极大减少了类型转换错误数量,并且显著提高了 Java 程序的稳定性。

代码 说明
public static void main(String[] args)
{
Object obj = new Tiger();
if (obj instanceof Cat)
{
Cat cat = (Cat) obj;
cat.doCatActions();
}}
更重要的是,使用 instanceof 检查
public static void main(String[] args)
{
Animal animal = new Tiger();
doAllAction(animal);

Animal animal2 = new Cat();
doAllAction(animal2);

Animal animal3 = new Animal();
doAllAction(animal3);
}

public static void doAllAction(Animal animal)
{
if (animal instanceof Tiger)
{
Tiger tiger = (Tiger) animal;
tiger.doTigerActions();
}

if (animal instanceof Cat)
{
Cat cat = (Cat) animal;
cat.doCatActions();
}

animal.doAnimalActions();
}
这就是原因所在。看看左侧的示例。

我们(我们的代码)并不总是了解我们使用的对象类型。它可能是与变量 (Animal) 相同类型的对象,也可能是后代类型 (Cat,Tiger) 的对象。

不妨考虑 doAllAction 方法。无论所传递的对象类型如何,它都可以正常运行。

换句话说,它可正确处理全部三种类型:Animal、Cat 和 Tiger。

public static void main(String[] args)
{
Cat cat = new Tiger(); Animal animal = cat; Object obj = cat;
}
这里有三个赋值运算。这些都是拓宽转换的例子。

这里不需要类型转换运算符,因为根本不需要检查。对象引用始终存储在其类型是祖先类型的变量中。

“哦,倒数第二个例子清楚地说明了一切:为何需要检查,以及为何需要类型转换。”

“我希望如此。我要提醒你注意这一点:“

这些都不会导致对象发生任何变化!唯一变化的是特定引用变量上可调用的方法数量

例如,Cat 变量可让你调用 doAnimalActions 和 doCatActions 方法。即使它指向 Tiger 对象,它也对 doTigerActions 方法一无所知。

“好,我明白了。这比我想象的要容易。”

评论 (16)
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION
Qin-1999 级别 22
11 一月 2024
这是什么格式啊!!

class Animal
{
public void doAnimalActions();
}class Cat extends Animal
{
public void doCatActions();
}class Tiger extends Cat
{
public void doTigerActions();
}
Qin-1999 级别 22
11 一月 2024

class Animal{public void doAnimalActions();}
class Cat extends Animal{public void doCatActions();}
class Tiger extends Cat{public void doTigerActions();}
还不如这么写
Qin-1999 级别 22
11 一月 2024

class Animal{public void doAnimalActions();}class Cat extends Animal{public void doCatActions();}class Tiger extends Cat{public void doTigerActions();}
一行写完算了
OldDog-Z124 级别 22,Germany,中国 Expert
7 九月 2023
1. 这些都不会导致对象发生任何变化!唯一变化的是特定引用变量上可调用的方法数量。
eupjcj 级别 1,China,China
5 十月 2023
求教下“特定引用变量上可调用的方法数量”是怎么变化的?
To be brave #10900452 级别 14,Пекин,China
26 一月 2022
多态
Yingjie Guan 级别 18,Quarry Bay
9 八月 2021
Object obj = new Tiger(); 这个是窄化吧,因为赋值后继承连向下移动了
z18335776829 级别 19,China,China
10 五月 2023
Object 是所有类的超类 Object是Animal的基类 Animal是Pet的基类 Pet是Cat的基类 Cat是Tiger的基类 也就说 几乎所有创建的类 都可以将实例的引用存放在 Object 类型的变量中
枫行 级别 41,China,China
30 九月 2023
错误的 Object是所有继承链的最上层
Tom 级别 41,San Jose,Sweden
4 二月 2021
老虎本來就是貓科動物
Kou Shikyo 级别 20,Tokyo
8 十月 2020
Tiger extends Cat 外国人都是这么想的??
kyrie 级别 18,重庆
11 六月 2021
。。。。遭不住 老虎本来就是猫科动物 Cat 指猫科
Tim Dai 级别 17,Tokyo,Japan
6 八月 2020
无权访问应该是语言问题。
Tim Dai 级别 17,Tokyo,Japan
7 八月 2020
Just sent email to support, let's see if it's resolved.
AE86 级别 20,Jinan
27 七月 2020
同问 只有这一节任务无权访问
吕海东 级别 20,Taiyuan,China
21 七月 2020
这一节的任务无权打开是为什么?