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

相关文章

Spring Boot整合Redis注解实现增删改查功能(Redis注解使用)

《SpringBoot整合Redis注解实现增删改查功能(Redis注解使用)》文章介绍了如何使用SpringBoot整合Redis注解实现增删改查功能,包括配置、实体类、Repository、Se... 目录配置Redis连接定义实体类创建Repository接口增删改查操作示例插入数据查询数据删除数据更

sqlserver、mysql、oracle、pgsql、sqlite五大关系数据库的对象名称和转义字符

《sqlserver、mysql、oracle、pgsql、sqlite五大关系数据库的对象名称和转义字符》:本文主要介绍sqlserver、mysql、oracle、pgsql、sqlite五大... 目录一、转义符1.1 oracle1.2 sqlserver1.3 PostgreSQL1.4 SQLi

Java Lettuce 客户端入门到生产的实现步骤

《JavaLettuce客户端入门到生产的实现步骤》本文主要介绍了JavaLettuce客户端入门到生产的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 目录1 安装依赖MavenGradle2 最小化连接示例3 核心特性速览4 生产环境配置建议5 常见问题

Java使用Swing生成一个最大公约数计算器

《Java使用Swing生成一个最大公约数计算器》这篇文章主要为大家详细介绍了Java使用Swing生成一个最大公约数计算器的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下... 目录第一步:利用欧几里得算法计算最大公约数欧几里得算法的证明情形 1:b=0情形 2:b>0完成相关代码第二步:加

Java 的ArrayList集合底层实现与最佳实践

《Java的ArrayList集合底层实现与最佳实践》本文主要介绍了Java的ArrayList集合类的核心概念、底层实现、关键成员变量、初始化机制、容量演变、扩容机制、性能分析、核心方法源码解析、... 目录1. 核心概念与底层实现1.1 ArrayList 的本质1.1.1 底层数据结构JDK 1.7

Java Map排序如何按照值按照键排序

《JavaMap排序如何按照值按照键排序》该文章主要介绍Java中三种Map(HashMap、LinkedHashMap、TreeMap)的默认排序行为及实现按键排序和按值排序的方法,每种方法结合实... 目录一、先理清 3 种 Map 的默认排序行为二、按「键」排序的实现方式1. 方式 1:用 TreeM

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,