文档章节

向上转型和向下转型

one_pieceD
 one_pieceD
发布于 2016/03/14 10:08
字数 1320
阅读 11
收藏 1

在Java编程中经常碰到类型转换,对象类型转换主要包括向上转型和向下转型。

5.13.1 向上转型

我们在现实中常常这样说:这个人会唱歌。在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念“人”。再例如,麻雀是鸟类的一种(鸟类的子类),而鸟类则是动物中的一种(动物的子类)。我们现实中也经常这样说:麻雀是鸟。这两种说法实际上就是所谓的向上转型,通俗地说就是子类转型成父类。这也符合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:

package a.b;

public class Monitor{

public void displayText() {}

public void displayGraphics() {}

}

液晶显示器类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可以不不作任何修改。

可以看出,向上转型体现了类的多态性,增强了程序的简洁性。

5.13.2 向下转型

子类转型成父类是向上转型,反过来说,父类转型成子类就是向下转型。但是,向下转型可能会带来一些问题:我们可以说麻雀是鸟,但不能说鸟就是麻雀。来看下面的例子:

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异常?使用5.7.7节学过的instanceof就可以了。我们修改一下C类的代码:

A a2 = new A();

if (a2 instanceof B) {

B b2 = (B) a2;

b2.aMthod();

b2.bMethod1();

b2.bMethod2();

}

这样处理后,就不用担心类型转换时发生ClassCastException异常了。


本文转载自:http://blog.csdn.net/shanghui815/article/details/6088588

共有 人打赏支持
下一篇: assert
one_pieceD
粉丝 0
博文 14
码字总数 9119
作品 0
杭州
私信 提问
接口回调 类向上转型 向下转型 (java)

1:接口回调 接口回调是指:可以把使用实现了某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口...

城固如春
2016/09/30
90
0
Java 多态方面的问题

public class Super { public int field=0; public int getField(){ return this.field; } } public class Sub extends Super{ public int field=1; public int getSuperField(){ return sup......

狂奔啦蜗牛
2012/06/07
392
6
怎么在Filter中使用HTTPServletRequest

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) re......

小姚
2012/03/22
0
0
Java基础1:深入理解Java面向对象三大特性

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a724888/article/details/80048732 这位大侠,这是我的公众号:程序员江湖。 分享程序员面试与技术的那些事。...

程序员江湖
2018/04/23
0
0
java问题,求大神分析明白啊,实在搞不懂了

对象的多态问题,向上转型和向下转型到底是怎么回事,搞不懂,看不懂,求指点。。

弈剑听雨阁小生
2013/04/30
526
4

没有更多内容

加载失败,请刷新页面

加载更多

容器服务

简介 容器服务提供高性能可伸缩的容器应用管理服务,支持用 Docker 和 Kubernetes 进行容器化应用的生命周期管理,提供多种应用发布方式和持续交付能力并支持微服务架构。 产品架构 容器服务...

狼王黄师傅
昨天
3
0
高性能应用缓存设计方案

为什么 不管是刻意或者偶尔看其他大神或者大师在讨论高性能架构时,自己都是认真的去看缓存是怎么用呢?认认真真的看完发现缓存这一块他们说的都是一个WebApp或者服务的缓存结构或者缓存实现...

呼呼南风
昨天
12
0
寻找一种易于理解的一致性算法(扩展版)

摘要 Raft 是一种为了管理复制日志的一致性算法。它提供了和 Paxos 算法相同的功能和性能,但是它的算法结构和 Paxos 不同,使得 Raft 算法更加容易理解并且更容易构建实际的系统。为了提升可...

Tiny熊
昨天
2
0
聊聊GarbageCollectionNotificationInfo

序 本文主要研究一下GarbageCollectionNotificationInfo CompositeData java.management/javax/management/openmbean/CompositeData.java public interface CompositeData { public Co......

go4it
昨天
3
0
阿里云ECS的1M带宽理解

本文就给大家科普下阿里云ECS的固定1M带宽的含义。 “下行带宽”和“上行带宽” 为了更好的理解,需要先给大家解释个词“下行带宽”和“上行带宽”: 下行带宽:粗略的解释就是下载数据的最大...

echojson
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部