1. 类型转换
存储引用类型(类)的变量也可以转换为不同的类型。但这仅适用于单一类型层次结构。让我们看一个简单的例子。假设我们有以下类层次结构,其中下面的类继承上面的类。

引用类型和原始类型的类型转换也被归类为扩大和缩小。
我们看到 Cat 类继承了 Pet 类,而 Pet 类又继承了 Animal 类。
如果我们这样写代码:
Animal kitten = new Cat();
这是一个扩大的类型转换。它也称为隐式转换。我们扩大了cat引用,现在它指向一个Cat对象。通过这样的类型转换,我们将无法使用kitten引用来调用Cat类中存在但Animal类中不存在的方法。
缩小转换(或显式转换)发生在相反的方向:
Cat cat = (Cat) kitten;
我们明确指出我们想要将存储在kitten变量(其类型为Animal)中的引用转换为Cat类型。
2.检查对象的类型
但是你在这里需要非常小心。如果你这样做:
Animal beast = new Cat();
Wolf grayWolf = (Wolf) beast;
编译器会允许这段代码,但是程序运行的时候会出现错误!JVM 会抛出一个异常:
Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to a Wolf
对Cat对象的引用只能存储在类型为 Cat 类的祖先的变量中:Pet、Animal 或 Object。
这是为什么?
这里的相关点是对象引用用于引用该对象的方法和变量。如果我们使用 Animal 变量来存储对 Cat 对象的引用,就不会有任何问题:Cat 类型始终具有 Animal 类型的变量和方法——它继承了它们!
但是如果 JVM 允许我们在 Wolf 变量中存储对 Cat 对象的引用,那么我们可能会遇到这样一种情况:我们可能会尝试使用 grayWolf 变量来调用存储在该变量中的 Cat 对象中不存在的方法. 这就是为什么这种安排是不允许的。
Java 有一个特殊的instanceof
运算符,可以让您检查对象是否属于某种类型,因此是否可以存储到某种类型的变量中。它看起来很简单:
variable instanceof Type
例子:
Animal beast = new Cat();
if (beast instanceof Wolf)
{
Wolf grayWolf = (Wolf) beast;
}
此代码不会导致错误 — 即使在运行时也是如此。
以下是一些说明情况的示例:
加宽类型转换 | 描述 |
---|---|
|
这是一个经典的扩大转换——不需要类型转换运算符。
|
缩小类型转换 | |
|
经典收缩转换:您需要添加类型检查和强制转换运算符。 变量 Cow cow 存储对对象的引用Whale 。 我们验证是这样的,然后进行(缩小)类型转换。或者它也被称为:
类型
转换
. |
|
您可以在不检查对象类型的情况下缩小引用类型。 如果 cow 变量引用的对象不是 a Whale ,则将InvalidClassCastException 生成 an 。 |
3.调用原始方法:super
关键字
当覆盖父类的方法时,有时我们不想用我们自己的方法替换它,而只是想稍微补充一下。
如果能在我们的方法中调用父类的方法,然后执行一些我们自己的代码就好了。或者也许先执行我们自己的代码,然后再调用父类的方法。
而 Java 让我们做到了这一点。要调用父类的方法,请执行以下操作:
super.method(arguments);
例子:
class PeaceTime
{
public double getPi()
{
return 3.14;
}
}
class WarTime extends PeaceTime
{
public double getPi()
{
return super.getPi()*2; // 3.14*2
}
}
战时,值Pi
可以大于6!当然,我们是在开玩笑,但这个例子演示了这一切是如何工作的。
这里有几个例子来澄清一些事情:
代码 | 描述 |
---|---|
|
Cow 和Whale 类 |
|
屏幕输出将是:
|
这是很难的事情。老实说,这是OOP中最难的事情之一。也就是说,您确实需要知道并理解它。
GO TO FULL VERSION