Java 之类型转换与多态详情
作者:Vamei
一、类型检查
Java的任意变量和引用经过类型声明
(type declaration
),才能使用。我们之前见过对象数据、类数据、方法参数、方法返回值以及方法内部的自动变量,它们都需要声明其类型。Java是一种强类型
(strongly typing
)语言,它会对类型进行检查。如果我们错误的使用类型,将造成错误。
比如在下面的Test类
中,我们将一个Cup类
对象赋予给aPerson类
引用:
public class Test { public static void main(String[] args) { Human aPerson; aPerson = new Cup(); } } class Human { /** * constructor */ public Human(int h) { this.height = h; } /** * accessor */ public int getHeight() { return this.height; } /** * mutator */ public void growHeight(int h) { this.height = this.height + h; } private int height; } class Cup { public void addWater(int w) { this.water = this.water + w; } public void drinkWater(int w) { this.water = this.water - w; } private int water = 0; }
javac将返回:
found : Cup required: Human aPerson = new Cup(); ^ 1 error
二、基本类型转换
Java可以对基本类型的变量进行类型转换。不同的基本类型有不同的长度和存储范围。如果我们从一个高精度类型转换到低精度类型,比如从float
转换到int
,那么我们有可能会损失信息。这样的转换叫做收缩变换(narrowing conversion
)。这种情况下,我们需要显示的声明类型转换,比如:
public class Test { public static void main(String[] args) { int a; a = (int) 1.23; // narrowing conversion System.out.println(a); } }
如果我们从低精度类型转换成高精度类型,则不存在信息损失的顾虑。这样的变换叫做宽松变换(widening conversion
)。我们不需要显示的要求类型转换,Java
可以自动进行:
public class Test { public static void main(String[] args) { int a = 3; double b; b = a; // widening conversion System.out.println(a); } }
基本类型转换流程图:
三、upcast与多态
在Java中,引用也可以进行类型转换,但是有限制。
我们可以将一个衍生类引用转换为其基类引用,这叫做向上转换(upcast
)或者宽松转换。下面的BrokenCup
类继承自Cup
类,并覆盖了Cup类
中原有的addWater
()和drinkWater
()方法:
public class Test { public static void main(String[] args) { Cup aCup; BrokenCup aBrokenCup = new BrokenCup(); aCup = aBrokenCup; // upcast aCup.addWater(10); // method binding } } class Cup { public void addWater(int w) { this.water = this.water + w; } public void drinkWater(int w) { this.water = this.water - w; } private int water = 0; } class BrokenCup extends Cup { public void addWater(int w) { System.out.println("shit, broken cup"); } public void drinkWater(int w) { System.out.println("om...num..., no water inside"); } }
程序运行结果:
shit, broken cup
在上面可以看到,不需要任何显示说明,我们将衍生类引用aBrokenCup赋予给它的基类引用aCup。类型转换将由Java自动进行。
我们随后调用了aCup
(我们声明它为Cup
类型)的addWater()
方法。尽管aCup
是Cup
类型的引用,它实际上调用的是BrokenCup
的addWater()
方法!也就是说,即使我们经过upcast
,将引用的类型宽松为其基类,Java
依然能正确的识别对象本身的类型,并调用正确的方法。Java
可以根据当前状况,识别对象的真实类型,这叫做多态(polymorphism
)。多态是面向对象的一个重要方面。
多态是Java
的支持的一种机制,同时也是面向对象的一个重要概念。这提出了一个分类学的问题,既子类对象实际上“是”父类对象。比如一只鸟,也是一个动物;一辆汽车,也必然是一个交通工具。Java
告诉我们,一个衍生类对象可以当做一个基类对象使用,而Java
会正确的处理这种情况。
比如下面的继承关系:
我们可以说用杯子(Cup
)喝水(drinkWater
)。实际上,喝水这个动作具体含义会在衍生类中发生很大变换。比如用吸管喝水,和从一个破杯子喝水,这两个动作差别会很大,虽然我们抽象中都讲“喝水”。我们当然可以针对每个衍生类分别编程,调用不同的drinkWater
方法。然而,作为程序员,我们可以对杯子编程,调用Cup
的drinkWater
()方法,而无论这个杯子是什么样的衍生类杯子。Java
会调用相应的正确方法,正如我们在上面程序中看到的。
看一个更加有意义的例子,我们给Human
类增加一个drink()
方法,这个方法接收一个杯子对象和一个整数作为参数。整数表示喝水的水量:
public class Test { public static void main(String[] args) { Human guest = new Human(); BrokenCup hisCup = new BrokenCup(); guest.drink(hisCup, 10); } } class Human { void drink(Cup aCup, int w) { aCup.drinkWater(w); } }
程序运行结果:
shit, no water inside
我们在Human
类的drink()
的定义中,要求第一个参量为Cup类型
的引用。但在实际运用时(Test类
),将Cup
的BrokenCup
衍生类对象。这实际上是将hisCup
向上转型称为Cup类
,传递给drink()方法
。在方法中,我们调用了drinkWater()方法
。Java发现这个对象实际上是BrokenCup
对象,所以实际调用了BrokenCup
的相应方法。
四、downcast
我们可以将一个基类引用向下转型(downcast
)成为衍生类的引用,但要求该基类引用所指向的对象,已经是所要downcast的衍生类对象
。比如可以将上面的hisCup
向上转型为Cup
类引用后,再向下转型成为BrokenCup
类引用。
五、Object类型
Java中,所有的类实际上都有一个共同的继承祖先
,即Object类
。Object类
提供了一些方法,比如toString()。
我们可以在自己的类定义中覆盖这些方法。
Object: 祖先
我们可以编写一个操作Object对象的程序,就可以通过upcast,将任意对象传递给该程序。
我将在以后深入Object类
多态的实现是依靠RTTI的支持
到此这篇关于Java 之类型转换与多态详情的文章就介绍到这了,更多相关Java 之类型转换与多态内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!