Java子类与父类之间的对象转换(说明继承)

2024-06-13 20:32

本文主要是介绍Java子类与父类之间的对象转换(说明继承),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

      在使用Java的多态机制时,常常使用的一个特性便是子类和父类之间的对象转换。从子类向父类的转换称为向上转换(upcasting),通过向上转换,我们能够在编写程序时采用通用程序设计的思想,在需要使用子类对象的时候,通过把变量定义为父类型,我们可以通过一个变量,使用该父类型的所有子类型实例;从父类型向子类型的转换称为向下转换(downcasting),通过向下转换,我们能在必要的时候,将父类型变量转换成子类型变量,使用一些通过子类型才能够使用的方法。以下是我对于对象转换的一些个人理解,如有不对,欢迎指正,虚心向大神们请教。

   首先是从子类向父类的向上转换。向上转换比较直观,总是能够将一个子类的实例转换为一个父类的对象,从继承链的角度,这个特性很容易理解:继承是一种“是一种”的关系,从父类派生出的子类,我们都能理解为,子类总是父类的一个实例。比如说,Fruit类派生出了Orange类,Apple类,Orange和Apple都是Fruit;Animal类派生出了Tiger类和Lion类,Tiger和Lion都是Animal。因此,从子类向父类的转换不需要什么限制,只需直接将子类实例赋值给父类变量即可,这也是Java中的多态的实现机制。

//Test.java
public class Test {public static void main(String args[]) {Animal tiger = new Tiger();Animal lion = new Lion();}
}class Animal {String name;Animal() {name = "animal";}Animal(String name) {this.name = name;}
}
class Tiger extends Animal {Tiger() {super("tiger");}
}
class Lion extends Animal {Lion() {super("lion");}
}


    然而从父类向子类的向下转换就稍微复杂一些了。在讲述向下转换之前,也许有些刚学java的朋友会有点不解为什么要使用向下转换,使用多态和动态绑定机制通过父类型变量使用子变量不就可以了么(比如我就曾对此感到疑惑)。这就要考虑到,在继承关系中,有一些方法是不适合由父类定义并由子类继承并重写的,有些方法是子类特有的,不应该通过继承得到,且子类可能也会有自己特有的成员变量,那么在使用多态机制的时候,若我们要通过父类型变量使用到这些子类特有的方法和属性的话,就需要将父类型变量转换成对应的子类型变量。一个典型例子便是标准库中的数据类型包装类:Integer类,Double类,Long类等,它们都继承自Number类,且它们都有一个方法叫做compareTo用于比较两个同样的类型。然而这个方法是这些子类通过实现Comparable接口来实现的,在Number类中并没有该方法的实现,因此若要通过Number类型变量来使用compareTo方法,就要先将Number类转换成子类的对象。

从父类向子类的转换就有限制了。首先,父类变量向子类转换必须通过显式强制类型转换,采取和向上转换相同的直接赋值方式是不行的,;并且,当把一个父类型变量实例转换为子类型变量时,必须确保该父类变量是子类的一个实例,从继承链的角度来理解这些原因:子类一定是父类的一个实例,然而父类却不一定是子类的实例;比如说,Fruit未必是Orange,它可能是Apple;Animal也不一定是Tiger,它可能是Lion。用代码来解释一下:

Animal tiger = new Tiger();
Animal lion = new Lion();

在前面向上转换的代码示例当中,main方法中的这两行代码,意思就是父类型变量tiger是子类Tiger的一个实例,lion是Lion的一个实例。 
也就是说,如果要把tiger转换为Tiger类型,必须保证tiger本身是Tiger的一个实例,在上例中,如果要把tiger转换成Lion类型,或是把Lion类型转换为Tiger类型,都是行不通的,在运行时,这会抛出一个运行异常ClassCastException,表示类转换异常。因此,在进行父类向子类的转换时,一个好的习惯是通过instanceof运算符来判断父类变量是否是该子类的一个实例:

Tiger t = null;
if(tiger instanceof Tiger)t = (Tiger)tiger;

如果要通过父类调用子类变量的方法,那么要注意要将父类型变量和强制转换用括号括起来:

Number i = new Integer(3);
System.out.println(((Integer)i).compareTo(new Integer(4)));

因为成员访问运算符.的优先级大于类型转换,所以要用括号括起来保证类型转换先于成员访问进行运算。 
前面说到用instanceof判断父类是否是子类的一个实例是一个好习惯,如果不养成这个习惯的话很容易出问题,请看下面这段代码:

Animal animal = new Tiger();
Lion lion = (Lion)tiger;

前面说到,这段代码会在运行时抛出ClassCastException异常,然而,这段代码却是能够编译成功的。原因是因为,Java编译器并没有聪明到能够在编译阶段就知道父类型变量是哪一个子类的实例,所以,将animal转换为Lion类型的代码:(Lion)animal是能够编译通过的,即使事实上我们能看到animal是Tiger的一个实例,因为Animal类型确实能转换成Lion类型,所以这条语句是合法的。所以,如果没有使用instanceof防止不同子类型之间的对象转换,而又不能指望编译器检查出这种转换逻辑错误的话,就很容易犯错了。

一、父类引用指向子类对象时

1、若子类覆盖了某方法,则父类引用调用子类重新定义的新方法

2、若子类未覆盖某方法,则父类引用调用父类本身的旧方法

3、若子类覆盖了某属性,但父类引用仍调用父类本身的旧属性

4、若子类未覆盖某属性,则父类引用调用父类本身的旧属性

5、父类引用不能访问子类新定义的属性和方法

二、子类引用指向自身对象时

1、若子类覆盖了某方法,则子类引用调用子类重新定义的新方法

2、若子类未覆盖某方法,则子类引用调用父类本身的旧方法

3、若子类覆盖了某属性,则子类引用调用子类重新定义的新属性

4、若子类未覆盖某属性,则子类引用调用父类本身的旧属性

5、子类引用可以访问子类新定义的方法

三、示例代码

B.java
[java]  view plain  copy
  1. public class B {  
  2.   
  3.     int a = 1;  
  4.     int b = 2;  
  5.   
  6.     void f1() {  
  7.         System.out.println("B.f1()");  
  8.     }  
  9.   
  10.     void f2() {  
  11.         System.out.println("B.f2()");  
  12.     }  
  13.   
  14. }  
C.java
[java]  view plain  copy
  1. public class C extends B {  
  2.   
  3.     int a = 3;  
  4.   
  5.     @Override  
  6.     void f1() {  
  7.         System.out.println("C.f1()");  
  8.     }  
  9.   
  10.     void f3() {  
  11.         System.out.println("C.f3()");  
  12.     }  
  13.   
  14.     public static void main(String[] args) {  
  15.   
  16.         B b = new C();// 父类引用指向子类对象  
  17.         b.f1();// 子类覆盖了该方法,所以父类引用调用新方法  
  18.         b.f2();// 子类未覆盖该方法,所以父类引用调用旧方法  
  19.         // b.f3();此行去掉注释会报错,父类引用不能访问子类新定义方法  
  20.         System.out.println(b.a);// 子类覆盖了该属性,但父类引用仍旧访问旧属性  
  21.         System.out.println(b.b);// 子类未覆盖该属性,父类访问旧属性  
  22.   
  23.         System.out.println();  
  24.   
  25.         C c = new C();// 子类引用指向自身对象  
  26.         c.f1();// 子类覆盖了父类方法,所以调用新方法  
  27.         c.f2();// 子类未覆盖父类方法,所以调用旧方法  
  28.         c.f3();// 子类调用自己新定义的方法  
  29.         System.out.println(c.a);// 子类覆盖了该属性,所以访问新属性  
  30.         System.out.println(c.b);// 子类未覆盖该属性,所以访问旧属性  
  31.     }  
  32. }  

输出:
[html]  view plain  copy
  1. C.f1()  
  2. B.f2()  
  3. 1  
  4. 2  
  5.   
  6. C.f1()  
  7. B.f2()  
  8. C.f3()  
  9. 3  
  10. 2  


这篇关于Java子类与父类之间的对象转换(说明继承)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1058348

相关文章

Java中StopWatch的使用示例详解

《Java中StopWatch的使用示例详解》stopWatch是org.springframework.util包下的一个工具类,使用它可直观的输出代码执行耗时,以及执行时间百分比,这篇文章主要介绍... 目录stopWatch 是org.springframework.util 包下的一个工具类,使用它

Java进行文件格式校验的方案详解

《Java进行文件格式校验的方案详解》这篇文章主要为大家详细介绍了Java中进行文件格式校验的相关方案,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、背景异常现象原因排查用户的无心之过二、解决方案Magandroidic Number判断主流检测库对比Tika的使用区分zip

Java实现时间与字符串互相转换详解

《Java实现时间与字符串互相转换详解》这篇文章主要为大家详细介绍了Java中实现时间与字符串互相转换的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、日期格式化为字符串(一)使用预定义格式(二)自定义格式二、字符串解析为日期(一)解析ISO格式字符串(二)解析自定义

Java使用Curator进行ZooKeeper操作的详细教程

《Java使用Curator进行ZooKeeper操作的详细教程》ApacheCurator是一个基于ZooKeeper的Java客户端库,它极大地简化了使用ZooKeeper的开发工作,在分布式系统... 目录1、简述2、核心功能2.1 CuratorFramework2.2 Recipes3、示例实践3

Springboot处理跨域的实现方式(附Demo)

《Springboot处理跨域的实现方式(附Demo)》:本文主要介绍Springboot处理跨域的实现方式(附Demo),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录Springboot处理跨域的方式1. 基本知识2. @CrossOrigin3. 全局跨域设置4.

springboot security使用jwt认证方式

《springbootsecurity使用jwt认证方式》:本文主要介绍springbootsecurity使用jwt认证方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录前言代码示例依赖定义mapper定义用户信息的实体beansecurity相关的类提供登录接口测试提供一

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

基于SpringBoot实现文件秒传功能

《基于SpringBoot实现文件秒传功能》在开发Web应用时,文件上传是一个常见需求,然而,当用户需要上传大文件或相同文件多次时,会造成带宽浪费和服务器存储冗余,此时可以使用文件秒传技术通过识别重复... 目录前言文件秒传原理代码实现1. 创建项目基础结构2. 创建上传存储代码3. 创建Result类4.

Java利用JSONPath操作JSON数据的技术指南

《Java利用JSONPath操作JSON数据的技术指南》JSONPath是一种强大的工具,用于查询和操作JSON数据,类似于SQL的语法,它为处理复杂的JSON数据结构提供了简单且高效... 目录1、简述2、什么是 jsONPath?3、Java 示例3.1 基本查询3.2 过滤查询3.3 递归搜索3.4

Tomcat版本与Java版本的关系及说明

《Tomcat版本与Java版本的关系及说明》:本文主要介绍Tomcat版本与Java版本的关系及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Tomcat版本与Java版本的关系Tomcat历史版本对应的Java版本Tomcat支持哪些版本的pythonJ