Java——超类和子类对象之间的转换

2023-11-11 05:48

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

继承是Java中常用的一项特性,通过继承我们可以省去很多麻烦。

而Java中超类和子类对象之间的转换则是很多新手的常遇见的难题,要是处理不好,恐怕会因为这个很特殊的问题导致一些潜在的危险,让你整整一个晚上都在调试程序以解决一个让人抓狂的java.lang.ArrayStoreException异常。 

哈哈,所谓救人一bug胜造七级浮屠,今天我们就来理一理Java中超类和子类对象之间的转换,看看它到底有什么不一样!

首先我们要了解一下转换的概念。

从子类向父类的转换称为向上转换(upcasting),通过向上转换,我们能够在编写程序时采用通用程序设计的思想,在需要使用子类对象的时候,通过把变量定义为父类型,我们可以通过一个变量,使用该父类型的所有子类型实例;从父类型向子类型的转换称为向下转换(downcasting),通过向下转换,我们能在必要的时候,将父类型变量转换成子类型变量,使用一些通过子类型才能够使用的方法。

那什么时候可以进行转换呢?

我们先来说一说向上转换,这个比较简单,而且限制还少。

还是老规矩,我们下面来看一段代码~~

来呀!!阿福,放代码~~~

                        class  Father{};class Son extends  publc  Father{    };

在上面的程序中Father为超类,son是father的子类

那如何将子类转换为超类呢?

  Father  f  =   new  Son();  //父类引用指向子类对象

 显然,这样就可以了。需要注意,new  Son()表示在在堆中分配了一段空间来存放类Son中的数据,并返回一个Son的对象,并赋值给Father的引用f,即f指向子类的对象,此时,子类的对象并没有定义一个名字。

 也就是说上面的语句等价于:

                           Son  s  =   new  Son();

                            Father  f  =  s;
注:父类不可调用子类新增的方法,即f不可调用s新增的方法。

好啦,子类转父类就是这样简单,接下来该重点看看父类转子类啦。

按理论上分析的话,父类转子类是不可以实现的。因为子类继承于父类,并新增了一些父类并没有的东西,也就是说,子类对象一般都比父类对象包含更多的东西。这样的话,子类如果访问子类新增的内容, 而这些内容父类并没有,所以就会报错。

那Java里面父类到底可不可以转子类呢?

可以!但是需要满足一个前提,即该父类对象已经指向了子类对象。

如:

                      Father  f  =   new  Son();  //父类引用指向子类对象

                      Son   s2  =  (Son)f;  //可以

                      因为当子类强制转换为父类对象时,并没有实际丢失它原有内存空间(比父类多的那些部分)

                      只是暂时不可访问,所以能再转回来。

此外,当该父类是调用子类构造器创建的时候,它也可以转换为子类。

如:

Employee b=new Manager("a",1000,2,1,225);//父类调用子类的构造器 创建了一个父类对象

这个原理其实和上面的情况一样,因为它也是父类引用指向了子类对象,因此也可以进行转换。

 当然,为了防止报ClassCastExcept异常,一般可以在前面加一条判断句 if(father instanceof Son)

                  如:

                        Father  f  =   new  Son();  //父类引用指向子类对象

                        if(father instanceof Son)

                       {

                                 Son   s2  =  (Son)f;

                      }

这样就可以避免出错。

通过上文的了解,大家可能心里已经有了一些理解,最后再提一下对象在继承关系中的改变

对象的赋值是地址标识的传递,即两个对象名共同使用同一段内存地址。在Java中,对父类与子类对象之间的赋值作了如下规定:

1、子类对象名可以赋值给父类对象名;但父类对象名不可以赋值给子类对象名。

即:父类对象名=子类对象名;

2、如果一个父类对象名已经被子类对象名所赋值,那可以将父类对象名经强制转换赋值给子类对象名。

即:子类对象名=(子类类名)父类对象名;

常用的一种形式:方法中形参用父类型,实参用子类的对象名.

总结

对类进行造型转换的应参考以下原则:
1.总是可以“父=子”赋值。此时不需要类型转换。
2.可以执行类型转换“子=(子)父”,但需要运行时进行检查。如果父类变量引用的是正确的子类型,赋值将执行。如果父类变量引用的是不相关的子类型,将会生成class castException异常。
即:如果父类的实例是在子类的实例上塑造的,“子=(子)父”时就不会抛出异常。  
如:
A 是B的父类。
A a= new B(); //父类A的对象a是在子类B的对象上塑造的。
就可以:
B b= (B)a;
3.决不能在不相关的任何类之间执行类的赋值或者类型转换。即类的造型转换仅限于有继承关系的俩个类的对象之间。

 

好啦,如果大家还是不太明白,可以试一试下面的程序,亲自上手试一试会了解得更透彻一些。

package inheritance;public class test {public static void main(String[] args) {// TODO Auto-generated method stubEmployee e;Manager boss =new Manager("Searchin",52000,2018,10,25);Employee[] staff=new Employee[3];staff[0]=boss;//子类转父类Employee b=new Manager("a",1000,2,1,225);//父类调用子类的构造器 创建了一个父类对象//Manager b=new Employee("a",1000,2,1,225);Manager a=(Manager)staff[0];//强制类型转换System.out.println(staff[0].getName());System.out.println(a.getName());boss.setBonus(5000);//staff[0].setBonus(5000);}}


 

package inheritance;import java.time.*;public class Employee
{private String name;private double salary;private LocalDate hireDay;public Employee(String name, double salary, int year, int month, int day){this.name = name;this.salary = salary;hireDay = LocalDate.of(year, month, day);}public String getName(){return name;}public double getSalary(){return salary;}public LocalDate getHireDay(){return hireDay;}public void raiseSalary(double byPercent){double raise = salary * byPercent / 100;salary += raise;}
}
package inheritance;public class Manager extends Employee
{private double bonus;public Manager(String name, double salary, int year, int month, int day){super(name, salary, year, month, day);bonus = 0;}public double getSalary(){double baseSalary = super.getSalary();return baseSalary + bonus;}public void setBonus(double b){bonus = b;}
}

 

这篇关于Java——超类和子类对象之间的转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

springboot集成easypoi导出word换行处理过程

《springboot集成easypoi导出word换行处理过程》SpringBoot集成Easypoi导出Word时,换行符n失效显示为空格,解决方法包括生成段落或替换模板中n为回车,同时需确... 目录项目场景问题描述解决方案第一种:生成段落的方式第二种:替换模板的情况,换行符替换成回车总结项目场景s

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

线上Java OOM问题定位与解决方案超详细解析

《线上JavaOOM问题定位与解决方案超详细解析》OOM是JVM抛出的错误,表示内存分配失败,:本文主要介绍线上JavaOOM问题定位与解决方案的相关资料,文中通过代码介绍的非常详细,需要的朋... 目录一、OOM问题核心认知1.1 OOM定义与技术定位1.2 OOM常见类型及技术特征二、OOM问题定位工具

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏