在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:

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异常了。

java向上和向下的区别_Java的向上和向下转型相关推荐

  1. java 文件夹下的文件_java读取某个文件夹下的所有文件

    import java.io.FileNotFoundException; import java.io.IOException; import java.io.File; public class  ...

  2. JAVA中重写和实现的区别_Java中重载和重写的区别

    Java中重载和重写的区别 1.1重载是什么 Overloading   方法重载是让类以统一的方式处理不同类型数据的一种手段,多个同名函数同时存在,具有不同的参数个数/类型 1.2为什么用重载 重载 ...

  3. java中int和integer的区别_Java异常中throw和throws关键字的区别

    Java中常常弄混的两个关键字,throw和throws,它们有什么区别呢?如何记忆他们,而不至于出错呢? throw和throws 区别 throws:出现在方法的签名中,声明当前方法可能抛出的所有 ...

  4. Java传统的io和nio区别_Java中IO和NIO的本质和区别

    简介 终于要写到java中最最让人激动的部分了IO和NIO.IO的全称是input output,是java程序跟外部世界交流的桥梁,IO指的是java.io包中的所有类,他们是从java1.0开始就 ...

  5. java中string 和stringbuffer的区别_Java中的String,StringBuilder,StringBuffer三者的区别...

    最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...

  6. java字符流和字节流的区别_java字符流与字节流的区别是什么

    java中字符流与字节流的区别: 1.字节流操作的基本单元为字节:字符流操作的基本单元为Unicode码元. 2.字节流默认不使用缓冲区:字符流使用缓冲区. 3.字节流通常用于处理二进制数据,实际上它 ...

  7. java 策略模式和工厂模式区别_Java编程细节——什么是策略模式

    策略模式应该是Java设计模式中最简单的一种模式, 它的核心思想是,一个类的行为可以在运行时动态改变,有不同的实现逻辑. 其实具体的说,它也是基于面向接口编程的思想,通过定义不同的实现类逻辑来做到的. ...

  8. java可比较的和比较器的区别_Java中Compareable和Comparator两种比较器的区别

    对于JDK8而言,有三种实现对象比较的方法: 1.在需要比较的对象类中覆写Object类的equals()方法: 2.需要比较的类继承Comparable接口,然后在其类内部实现compareTo() ...

  9. Java的流读一行丢一行_java – 在少数特定情况下记录丢失的消息

    我正在使用 java.util.logging来完成我的应用程序的所有日志记录. 直到最近,我在没有任何特定配置的情况下使用日志工具.一切都按预期工作,所有日志都在控制台中可见(stderr) 现在, ...

最新文章

  1. redhat linux新建用户,linux redhat 添加用户
  2. web前端知识体系大全
  3. VS2010下安装boost库
  4. 如何快速在Linux系统的硬盘上创建大文件
  5. sqlplus命令行登录oracle数据库的N种方法盘点
  6. 震惊,用了这么多年的 CPU 利用率,其实是错的
  7. wps表格里面计算机在哪里,WPS的Word居然还有计算神器?在哪里能找到又是怎么进行计算呢?...
  8. 图解后缀表达式的计算过程
  9. varnish与squid比较
  10. C语言-目标文件/链接文件
  11. PAT 乙级 1023. 组个最小数 (20) Java版
  12. jmeter无法启动的解决办法
  13. TI DSP 28335 自学之路,到此止步
  14. 360屏保壁纸android,“如何删除屏保和壁纸”的解决方案
  15. 用计算机弹极乐净土谱,极乐净土计算器谱子
  16. 基于python的垃圾分类程序,提供数据集(pytorch开发)
  17. Navicat操作mysql遇问题1142-create command denied to user×××的解决
  18. xilinx IP 汇总
  19. 群晖如何实现不在同一网段的访问
  20. 网易双11“超级工程”:反欺诈系统应用实践

热门文章

  1. HALCON 20.11:深度学习笔记(12)---语义分割
  2. 有了malloc/free为什么还要new/delete ?
  3. OpenCV分水岭分割函数:watershed()介绍
  4. nginx简介(轻量级开源高并发web服务器:大陆使用者百度、京东、新浪、网易、腾讯、淘宝等)(并发量5w)(一般网站apache够用了,而且稳定)...
  5. 程序包OE_Order_PUB过程 Process_.Order 中出现错误ORA-20001
  6. Oracle 12C 新特性之扩展数据类型(extended data type)
  7. 20个开发人员非常有用的Java功能代码(二)
  8. HTML5 中的 canvas 画布(二)
  9. 艾伟_转载:.NET设计模式:工厂方法模式(Factory Method)
  10. Socket开发探秘--基于Json格式的数据协议收发