Java 转型(向上或向下转型)详解及简单实例

 更新时间:2017年02月27日 11:47:17   投稿:lqh  
这篇文章主要介绍了Java 转型(向上或向下转型)详解及简单实例的相关资料,需要的朋友可以参考下

在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可以不不作任何修改。

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

向下转型

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

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

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • 关于线程池异步线程中再次获取线程池资源的问题

    关于线程池异步线程中再次获取线程池资源的问题

    这篇文章主要介绍了关于线程池异步线程中再次获取线程池资源的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • java中springMVC获取请求参数的方法

    java中springMVC获取请求参数的方法

    这篇文章主要介绍了java中springMVC获取请求参数的方法,springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合,需要的朋友可以参考下
    2023-05-05
  • java打包文件成zip、压缩文件及file.mkdir和mkdirs的区别详解

    java打包文件成zip、压缩文件及file.mkdir和mkdirs的区别详解

    这篇文章主要给大家介绍了关于java打包文件成zip、压缩文件及file.mkdir和mkdirs区别详解的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-12-12
  • Java基于线程实现带有滚动效果的Label标签实例

    Java基于线程实现带有滚动效果的Label标签实例

    这篇文章主要介绍了Java基于线程实现带有滚动效果的Label标签,实例分析了java线程的使用技巧及label标签的实现方法,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • 解决mybatis plus 驼峰式命名规则问题

    解决mybatis plus 驼峰式命名规则问题

    这篇文章主要介绍了解决mybatis plus 驼峰式命名规则,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java 仿天猫服装商城系统的实现流程

    Java 仿天猫服装商城系统的实现流程

    读万卷书不如行万里路,只学书上的理论是远远不够的,只有在实战中才能获得能力的提升,本篇文章手把手带你用java+SSM+jsp+mysql+maven实现一个仿天猫服装商城系统,大家可以在过程中查缺补漏,提升水平
    2021-11-11
  • Kotlin基础教程之面向对象

    Kotlin基础教程之面向对象

    这篇文章主要介绍了Kotlin基础教程之面向对象的相关资料,需要的朋友可以参考下
    2017-05-05
  • Java如何在PPT中绘制图形

    Java如何在PPT中绘制图形

    这篇文章主要介绍了Java如何在PPT中绘制图形,Microsoft PowerPoint可支持在幻灯片中插入各种类型的图形并且可设置图形填充、线条颜色、图形大小、位置等。下面将通过Java编程来演示在PPT中绘制图形的方法,需要的朋友可以参考下
    2019-07-07
  • 应用Java泛型和反射导出CSV文件的方法

    应用Java泛型和反射导出CSV文件的方法

    这篇文章主要介绍了应用Java泛型和反射导出CSV文件的方法,通过一个自定义函数结合泛型与反射的应用实现导出CSV文件的功能,具有一定的参考借鉴价值,需要的朋友可以参考下
    2014-12-12
  • SpringMVC4.3 HttpMessageConverter接口实现源码分析

    SpringMVC4.3 HttpMessageConverter接口实现源码分析

    这篇文章主要为大家介绍了SpringMVC4.3 HttpMessageConverter接口实现源码分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09

最新评论