在Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型。
向上转型
我们在现实中常常这样说:这个人会唱歌。在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念“人”。再例如,麻雀是鸟类的一种(鸟类的子类),而鸟类则是动物中的一种(动物的子类)。我们现实中也经常这样说:麻雀是鸟。这两种说法实际上就是所谓的向上转型,通俗地说就是子类转型成父类。这也符合Java提倡的面向抽象编程思想。来看下面的代码:
package a.b;
public class A {
public void a1() {
System.out.println("Superclass");
}
}
//A的子类B:
package a.b;
public class B extends A {
public void a1() {
System.out.println("Childrenclass"); //覆盖父类方法
}
public void b1(){} //B类定义了自己的新方法
}
//C类:
package a.b;
public class c {
public static void main(String[] args) {
A a = new B(); //向上转型
a.a1();
}
}
如果运行C,输出的是Superclass 还是Childrenclass?不是你原来预期的Superclass,而是Childrenclass。这是因为a实际上指向的是一个子类对象。当然,你不用担心,Java虚拟机会自动准确地识别出究竟该调用哪个具体的方法。不过,由于向上转型,a对象会遗失和父类不同的方法,例如b1()。有人可能会提出疑问:这不是多此一举吗?我们完全可以这样写:
B a = new B();
a.a1();
确实如此!但这样就丧失了面向抽象的编程特色,降低了可扩展性。其实,不仅仅如此,向上转型还可以减轻编程工作量。来看下面的显示器类Monitor:
<span style="font-size:18px;">package a.b;
public class Monitor{
public void displayText() {}
public void displayGraphics() {}
}
</span>
液晶显示器类LCDMonitor是Monitor的子类:
package a.b;
public class LCDMonitor extends Monitor {
public void displayText() {
System.out.println("LCD display text");
}
public void displayGraphics() {
System.out.println("LCD display graphics");
}
}
阴极射线管显示器类CRTMonitor自然也是Monitor的子类:
package a.b;
public class CRTMonitor extends Monitor {
public void displayText() {
System.out.println("CRT display text");
}
public void displayGraphics() {
System.out.println("CRT display graphics");
}
}
等离子显示器PlasmaMonitor也是Monitor的子类:
package a.b;
public class PlasmaMonitor extends Monitor {
public void displayText() {
System.out.println("Plasma display text");
}
public void displayGraphics() {
System.out.println("Plasma display graphics");
}
}
现在有一个MyMonitor类。假设没有向上转型,MyMonitor类代码如下:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor());
run(new CRTMonitor());
run(new PlasmaMonitor());
}
public static void run(LCDMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
public static void run(CRTMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
public static void run(PlasmaMonitor monitor) {
monitor.displayText();
monitor.displayGraphics();
}
}
可能你已经意识到上述代码有很多重复代码,而且也不易维护。有了向上转型,代码可以更为简洁:
package a.b;
public class MyMonitor {
public static void main(String[] args) {
run(new LCDMonitor()); //向上转型
run(new CRTMonitor()); //向上转型
run(new PlasmaMonitor()); //向上转型
}
public static void run(Monitor monitor) { //父类实例作为参数
monitor.displayText();
monitor.displayGraphics();
}
}
我们也可以采用接口的方式,例如:
package a.b;
public interface Monitor {
abstract void displayText();
abstract void displayGraphics();
}
将液晶显示器类LCDMonitor稍作修改:
package a.b;
public class LCDMonitor implements Monitor {
public void displayText() {
System.out.println("LCD display text");
}
public void displayGraphics() {
System.out.println("LCD display graphics");
}
}
CRTMonitor、PlasmaMonitor类的修改方法与LCDMonitor类似,而MyMonitor可以不不作任何修改。
可以看出,向上转型体现了类的多态性,增强了程序的简洁性。
向下转型
子类转型成父类是向上转型,反过来说,父类转型成子类就是向下转型。但是,向下转型可能会带来一些问题:我们可以说麻雀是鸟,但不能说鸟就是麻雀。来看下面的例子:
A类:
package a.b;
public class A {
void aMthod() {
System.out.println("A method");
}
}
A的子类B:
package a.b;
public class B extends A {
void bMethod1() {
System.out.println("B method 1");
}
void bMethod2() {
System.out.println("B method 2");
}
}
C类:
package a.b;
public class C {
public static void main(String[] args) {
A a1 = new B(); // 向上转型
a1.aMthod(); // 调用父类aMthod(),a1遗失B类方法bMethod1()、bMethod2()
B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误
b1.aMthod(); // 调用父类A方法
b1.bMethod1(); // 调用B类方法
b1.bMethod2(); // 调用B类方法
A a2 = new A();
B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
}
从上面的代码我们可以得出这样一个结论:向下转型需要使用强制转换。运行C程序,控制台将输出:
Exception in thread "main" java.lang.ClassCastException: a.b.A cannot be cast to a.b.B at
a.b.C.main(C.java:14)
A method
A method
B method 1
B method 2
其实向下转型代码后的注释已经提示你将发生运行时错误。为什么前一句向下转型代码可以,而后一句代码却出错?这是因为a1指向一个子类B的对象,所以子类B的实例对象b1当然也可以指向a1。而a2是一个父类对象,子类对象b2不能指向父类对象a2。那么如何避免在执行向下转型时发生运行时ClassCastException异常?使用学过的instanceof就可以了。我们修改一下C类的代码:
A a2 = new A();
if (a2 instanceof B) {
B b2 = (B) a2;
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
这样处理后,就不用担心类型转换时发生ClassCastException异常了。
分享到:
相关推荐
Java程序设计课件:第一章 初次邂逅Java.ppt
"天生一对——邂逅情人节ppt模板.rar" 提供的是一份特别设计的情人节主题PPT模板,它融合了创新与趣味元素,旨在帮助用户快速创建出吸引人的情人节展示。这份模板可能包含了一系列精心设计的幻灯片布局、色彩搭配、...
语文邂逅电商,聚焦共生共融——“语文 电商”跨界融合的“珍珠饰品图文编排”课例研究.pdf
江凌梅在其研究《邂逅统编教科书——借文本解读促小学语文课堂深度学习研究》中,探讨了如何利用统编教科书,通过文本解读的方式,来促进小学生对语文学科的深度学习。 在文章中,江凌梅提出了几个促进深度学习的...
我们生活在电气时代。电渗透到我们日常生活中的方方面面。没有了电,我们的世界是黑暗的,没有了电,我们恐怕已经不知道该怎么生活。众所周知,是英国物理学家迈克尔·法拉第(Michael Faraday,1791-1867)将这伟大...
Java Web编程宝典-十年典藏版.pdf 是PDF电子书,不是源码。共分2个包。 《Java Web编程宝典(十年典藏版)》是一本集技能、范例、项目和应用为一体的学习手册,书中介绍了应用Java Web进行程序开发的各种技术、技巧。...
在如今车市竞争日益激烈的背景下,各大汽车品牌都在努力寻求有效的市场策略以提升自身产品的市场地位和品牌影响力。第七代天籁ALTIMA作为中高级轿车市场的后起之秀,面临着既有竞品市场份额牢固和新晋竞争者不断涌现...
认识Vuejs 1 为什么学习Vuejs? 前端必备技能,目前非常火,当然最重要的还是提升自己 2.简单认识一下Vuejs Vue是一个渐进式框架,可以将Vue作为应用的一部分嵌入其中,带来更丰富的交互体验 特点:解耦视图和数据,...
根据提供的信息,我们可以总结出以下相关的Java编程知识点: ### 一、Java图形用户界面(GUI)编程 #### 1.1 使用Swing构建GUI 在本示例代码中,使用了Swing库来创建一个图形用户界面。Swing是Java中的一个用于...
桃花般的女子,不仅代表了一种美好与邂逅,更是将人们引向更深层次的情感体验,如浪漫的一见钟情、遗憾和痛苦等复杂情绪。这里所描绘的美丽邂逅,不仅仅是相遇那么简单,它可能成为我们记忆中的一个深刻印记,影响着...
在当前信息化社会中,教育与各行各业的交叉融合已经成为一种趋势,"语文邂逅电商"就是一个典型的例子,展示了教育如何与新兴领域相结合,培养更具时代特色的技能。本课例研究主要探讨了语文教学如何与电子商务相互...
### 邂逅秋天——从文学角度理解秋天的魅力 #### 秋天的多重意象 秋天是一个充满变化的季节,不同的人对秋天的感受也不尽相同。在《邂逅秋天》的几篇作文中,作者通过不同的场景描绘了秋天的多重面貌,包括**树林**...
社交零售领域的上市公司通过年度财报能够向投资者展示其业务情况,同时财报分析有助于投资者发现和了解企业的内在价值,通过数字来理解企业的战略方向和运营效率。 中国社交零售领域的直销和电商上市企业在经历过去...
在这充满生机的季节里,我们有幸邂逅一份特别的礼物——《邂逅春天花海PPT模板》。这款模板不仅是展示春天美景的画卷,更是一段关于时间、空间与情感交融的旅程。 随着油菜花海的金黄色铺展,春天正式地在我们眼前...
他们的邂逅揭示了看似截然不同的人生背后,两颗渴望共鸣的灵魂。弗朗西斯卡在罗伯特的镜头下,找到了自我,她那被日常琐碎生活压抑的激情被唤醒。这种灵魂的共鸣,使他们在短短四天内,经历了深深的相爱。 爱情在...
------------异常处理程序<BR><BR>12.5一个异常处理的简单实例:除数为0<BR><BR>需求:使用一个小应用程序,完成两数相除的计算<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>分析:我们使用有顶向下,逐步求精的方法:...
今年的光棍节,中山市兴中广场的幻彩摩天轮下,将举行一场名为“邂逅摩天轮,邂逅爱”的特别活动,为单身的你我他,提供一个浪漫而又充满机遇的交友平台。 兴中广场的幻彩摩天轮,以其独特的位置和设计,成为中山市...
春之约会,草长莺飞的三月,正是油菜花盛开的季节,邂逅了油菜花的我,与春天有一场美丽的约会;邂逅春天,三月,在微风暖阳中,悄悄溜走,花谢花开,此事,无关风月。华中农业大学院部简介,校园转角,茶树的形象...