【Java】:向上转型、向下转型和ClassCastException异常

news2024/11/24 12:28:29

目录

先用一个生动形象的例子来解释向上转型和向下转型

向上转型(Upcasting)

向下转型(Downcasting)

向上转型

概念

例子

发生向上转型的情况

1.子类对象赋值给父类引用

2.方法参数传递

3.返回值

向下转型

概念

注意事项

例子

ClassCastException异常

概念

例子


先用一个生动形象的例子来解释向上转型和向下转型

向上转型(Upcasting)

想象你有一个动物园,里面有各种不同类型的动物,如狮子、大象、长颈鹿等。动物园的管理员为了方便管理,给每种动物都发放了一个“动物身份证”。这个身份证上并没有详细标明是哪种动物,只是简单地标明“动物”。当管理员查看这些身份证时,他并不关心具体是哪种动物,只要知道它们是动物园里的“动物”就足够了。这就是向上转型的概念。

例子
假设你有一个Lion类(狮子类),它是Animal类(动物类)的子类。当你创建一个Lion对象,并将其赋值给一个Animal类型的引用时,就发生了向上转型。

Animal animal = new Lion(); // Lion对象被向上转型为Animal类型

在这个例子中,animal引用变量只知道它引用的是一个“动物”,而不知道具体是哪种动物。你可以通过animal引用调用Animal类中定义的方法,但不能调用Lion类中特有的方法。

向下转型(Downcasting)

现在,假设动物园的管理员需要对某种特定的动物进行特殊照顾,比如给狮子喂食特定的食物。这时,管理员需要从一堆“动物身份证”中找到狮子的身份证,并将其视为“狮子身份证”。这就是向下转型的概念。

例子
继续上面的例子,如果你想通过animal引用调用Lion类中特有的方法(比如roar()方法,表示狮子吼叫),你需要先将animal引用向下转型为Lion类型。

if (animal instanceof Lion) { // 先检查animal引用是否确实指向Lion对象  
    Lion lion = (Lion) animal; // Animal类型被向下转型为Lion类型  
    lion.roar(); // 现在可以调用Lion类中特有的方法了  
}

在这个例子中,你首先使用instanceof运算符检查animal引用是否确实指向一个Lion对象。如果是,你就可以安全地进行向下转型,并调用Lion类中特有的方法。


向上转型

概念


向上转型(Upcasting)是 面向对象编程 中的一个概念,特指将一个子类对象赋值给一个父类类型的引用变量。
这是多态性的一种体现,因为子类对象是父类的一个特例。
在Java中,向上转型是安全的,因为子类继承了父类的所有属性和方法(除了私有方法和构造方法)。

例子

假设有一个父类 Fruit 和子类 Apple

class Fruit {  
    void eat() {  
        System.out.println("Eating fruit");  
    }  
}  
  
class Apple extends Fruit {  
    @Override  
    void eat() {  
        System.out.println("Eating an apple");  
    }  
}

现在,如果我们有一个 Apple 对象,我们可以将它向上转型为 Fruit 类型:

public class Main {  
    public static void main(String[] args) {  
        Apple apple = new Apple();  
        Fruit fruit = apple; // 向上转型  
        //也可写做:Fruit fruit = new Apple();
        fruit.eat(); // 输出 "Eating an apple",因为实际调用的是 Apple 类的 eat 方法  
    }  
}

在这个例子中,Apple 类的实例 apple 被向上转型为 Fruit 类型,并赋值给 fruit 变量。

尽管 fruitFruit 类型,但由于多态性,调用 eat() 方法时实际上会执行 Apple 类中重写的 eat() 方法。

这就是向上转型和多态性的实际应用。


发生向上转型的情况


1.子类对象赋值给父类引用

当子类的实例直接赋值给父类类型的引用时,会发生向上转型。这是最常见的向上转型场景。

Apple apple = new Apple();  
Fruit fruit = apple; // 向上转型
//也可写为:Fruit fruit = new Apple();

2.方法参数传递

当向一个接受父类类型参数的方法传递一个子类对象时,也会发生向上转型。

void processFruit(Fruit fruit) {  
    // ...  
}  

Apple apple = new Apple();  
processFruit(apple); // 在这里,apple被向上转型为Fruit类型

3.返回值

如果一个方法返回一个子类对象,但是方法的返回类型是父类,那么在返回时也会发生向上转型。

Fruit getFruit() {  
    Apple apple = new Apple();  
    return apple; // 在这里,apple被向上转型为Fruit类型返回  
}

向下转型

概念


向下转型(Downcasting)是Java中类型转换的一种,它指的是将一个父类对象转换为子类类型的全过程。这个过程是显式的,需要使用强制类型转换操作符来完成。

在Java中,子类拥有父类的所有属性和方法(除了 private 修饰的属性和方法),同事还可以定义自己特有的属性和方法。

因此,当我们需要将一个父类对象当做子类对象来使用的时候,就需要进行向下转型。

注意事项

  • 向下转型的语法格式如下:
子类类型 变量名 = (子类类型) 父类对象;

  •  只能对已经进行过向上转型的对象进行向下转型:

在Java中,我们不能直接将一个父类对象强制转换为子类对象,除非这个父类对象实际上是子类对象的向上转型。也就是说,我们必须先创建一个子类对象,然后将其向上转型为父类对象,最后再进行向下转换。


  • 向下转型时需要进行类型检查:

为了避免在运行时抛出 ClassCastException 异常,我们在进行向下转型之前,通常需要使用 instanceof 运算符来检查父类对象是否可以被转换为子类类型。


  • 注意访问权限:

在向下转型后,我们可以访问子类特有的属性和方法。但是需要注意的是,如果子类中的某些属性或者方法时 private 的,那么即使进行了向下转型,也无法直接访问这些 private 成员。

例子

下面是一个简单的例子来说明向下转型的用法:

class Animal {  
    void makeSound() {  
        System.out.println("Animal makes a sound");  
    }  
}  
  
class Dog extends Animal {  
    void bark() {  
        System.out.println("Dog barks");  
    }  
}  
  
public class Main {  
    public static void main(String[] args) {  
        Animal animal = new Dog(); // 向上转型,将Dog对象转型为Animal类型  
        if (animal instanceof Dog) { // 使用instanceof进行类型检查  
            Dog dog = (Dog) animal; // 向下转型,将Animal对象转型为Dog类型  
            dog.bark(); // 调用Dog类特有的方法bark()  
        } else {  
            System.out.println("The animal is not a dog.");  
        }  
    }  
}

在这个例子中,我们首先创建了一个 Dog 对象,并将其向上转型为Animal 类型。然后,我们使用 Instanceof 运算符检查这个 Animal 对象是否可以被转换为 Dog 类型。如果可以转换,我们就进行向下转型,将 Animal 对象转换为 Dog 类型,并调用 Dog 类特有的方法 bark() 。

ClassCastException异常

概念

ClassCastException是Java中的一个运行时异常,它发生在试图将一个对象强制转换为不是其实际类型的类类型时。换句话说,当你尝试将一个对象转型为它不兼容的类型时,就会抛出此异常。

这个异常通常发生在向下转型时,如果你没有正确地检查对象的实际类型就进行转换,可能会引发ClassCastException。在Java中,向上转型是安全的,因为子类对象是父类类型的一个特例。但是,向下转型则需要显式的类型转换,并且如果不当使用,就可能导致 ClassCastException。

例子

下面是一个会导致 ClassCastException 异常的例子:

class Animal {}  
  
class Dog extends Animal {}  
  
class Cat extends Animal {}  
  
public class Main {  
    public static void main(String[] args) {  
        Animal animal = new Cat(); 
// 向上转型,Cat 是Animal的子类,所以这是安全的  
        Dog dog = (Dog) animal; 
// 尝试向下转型,但是 animal 实际上是 Cat 类型,所以会抛出 ClassCastException  
    }  
}

在这个例子中,我们创建了一个 Cat 对象,并将其赋值给 Animal 类型的变量 animal。然后,我们尝试将这个 Animal 类型的变量强制转换为 Dog 类型。但是,因为这个 Animal 对象实际上是 Cat 类型的,所以转换会失败,并抛出一个 ClassCastException

为了避免这种异常,你可以在向下转型之前使用 instanceof 操作符来检查对象是否可以被安全地转换为目标类型:

if (animal instanceof Dog) {  
    Dog dog = (Dog) animal; // 这是安全的,因为已经检查了类型  
} else {  
    System.out.println("The animal is not a dog.");  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1667194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【数字IC设计】芯片设计中的RDC

RDC问题定义 在芯片设计中,RDC是reset domain crossing 的缩写,类似于CDC(clock domain crossing),由于现在SOC芯片是有很多ECUs组成,为了使整个系统能够快速从复位中恢复, 用户希望SOC里面每个ECU模块都可以有自己独立的异步复位信号,这样可以在出问题的时候只复位有错…

Java | Spring框架 | AOP代理机制

大家好,我是程序员影子,一名AI编程深耕者,点击左上角头像了解我的详细信息。 今天来聊一聊关于Java中的Spring AOP代理机制中的JDK动态代理与CGLIB。 一、JDK动态代理 JDK动态代理是Spring AOP默认使用的代理机制。它基于Java反射机制&…

IO:线程的同步互斥

一、引入 例: 要求定义一个全局变量 char buf[] "1234567",创建两个线程,不考虑退出条件。 A线程循环打印buf字符串, B线程循环倒置buf字符串,即buf中本来存储1234567,倒置后buf中存储7654321.…

【计算机毕业设计】基于微信小程序校友会系统的实现

由于APP软件在开发以及运营上面所需成本较高,而用户手机需要安装各种APP软件,因此占用用户过多的手机存储空间,导致用户手机运行缓慢,体验度比较差,进而导致用户会卸载非必要的APP,倒逼 管理者必须改变运营…

2024.5.9 关于 SpringCloud —— Nacos 的安装与配置

目录 Windos 安装步骤 docker 启动 nacos Windos 安装步骤 1)点击下方链接,进入并访问 nacos 官网 Nacos官网 | Nacos 官方社区 | Nacos 下载 | Nacos 2)按照下图箭头指示下载对应版本的压缩包 3)此时我们将得到一个压缩包&…

GDPU JavaWeb 过滤器

再纯净的白开水也过滤不了渣茶。 Servlet登陆页面 引入数据库,创建用户表,包括用户名和密码:客户端通过login.jsp发出登录请求,请求提交到loginServlet处理。如果用户名和密码跟用户表匹配则视为登录成功,跳转到loginS…

【iOS】RunLoop详解(二)

RunLoop详解(二) RunLoop 的概念RunLoop 与线程的关系RunloopRunloop与线程的关系RunLoop对外的接口Runloop的Mode举例说明小结 RunLoop 的内部逻辑RunLoop的底层实现苹果用RunLoop实现的功能AutoreleasePool事件响应手势识别界面更新定时器PerformSelec…

制作绿色便携式Chrome浏览器

准备环境 chrome离线解压包7zip解压缩软件Chrome Portable便携版启动程序 一、获取Chrome离线解压包 获取官方的离线下载包,使用7zip软件打开压缩包。如果里面看到的事102~表示是离线安装包,如果是chrome.7z表示是离线解压包。 如果是解压包的话&…

Git的安装和配置

一、Git的介绍 代码的一套托管工具,它分为两个仓库,首先将你写的代码提交到本地仓库,这个时候只有你可以看,和你一起开发的同事看不到。将本地仓库的代码推到远程仓库(githab、gitee、gitlab等之一)&#…

Deckset for Mac:让演示文稿制作更轻松

还在为繁琐的演示文稿制作而烦恼吗?Deckset for Mac来帮您解决!它支持Markdown语言,让您只需专注于内容的创作,无需在排版和设计上耗费过多精力。丰富的主题和布局选项,让您能够轻松打造出专业级的演示文稿。快来体验D…

docker 部署SSM项目(包含打包)

一:SSM项目打包 1.这个一定要勾选防止静态资源没打包上 2.第二步 3.第三步 4.更改名字(注意部署到线上的时候这里如果用docker或者window部署的话需要带这个项目名,不然会出现找不到接口的情况) ![在这里插入图片描述](https://img-blog.csdnimg.cn/dir…

CUDA backend requires cuDNN. Please resolve dependency or disable的解决方法

先把 C:\Program Files\NVIDIA\CUDNN\v9.0里面的bin,include,lib文件夹中最里面的文件 复制到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4中的bin,include,lib文件夹 你的路径或许有点不一样,但大概就是这样 注意,复制完后,文…

网络应用层

叠甲:以下文章主要是依靠我的实际编码学习中总结出来的经验之谈,求逻辑自洽,不能百分百保证正确,有错误、未定义、不合适的内容请尽情指出! 文章目录 1.使用协议和序列化1.1.自定义协议,自定义序列化1.2.自…

【python】使用requests爬取网页采集、单词翻译、豆瓣排行、kfc餐厅信息

目录 1.网页采集 2.单词翻译 ​编辑 3.豆瓣排行榜 4.kfs 餐厅信息 实现步骤:(1)指定url (2)发起请求 (3)获取响应数据 (4)持久化存储 1.网页采集 import requests …

day11-StreamFile

1.Stream流 1.1 体验Stream流 需求:按照下面的要求完成集合的创建和遍历 创建一个集合,存储多个字符串元素 把集合中所有以"杨"开头的元素存储到一个新的集合 把"杨"开头的集合中的长度为3的元素存储到一个新的集合 遍历上一步得到…

【数据结构】图的应用---最小生成树(Prim,Kruskal)、最短路径(BFS,Dijkstra,Floyd)、拓扑排序、关键路径、有向无环图表达式

文章目录 5.图的应用5.1 最小生成树5.1.1 Prim算法5.1.2 Kruskal算法5.1.3 最小生成树代码A.邻接矩阵B.邻接表 5.2 最短路径5.2.1 BFS5.2.2 Dijkstra5.2.3 Floyd5.2.4 三种算法的比较 5.3 有向无环图描述表达式5.4 拓扑排序5.5 关键路径 5.图的应用 5.1 最小生成树 定义 对一个…

uniapp获取当前位置及检测授权状态——支持App、微信小程序

uniapp获取当前位置检测及定位权限——支持App、微信小程序 首先,祝天下母亲,节日快乐~ 文章目录 uniapp获取当前位置检测及定位权限——支持App、微信小程序效果图新增 兼容小程序方法manifest Tips: 上一篇介绍 App端 uniapp获取当前位置及…

分布式与一致性协议之PBFT算法(二)

PBFT算法 如何替换作恶的主节点 虽然PBFT算法可以防止备份节点作恶,因为这个算法是由主节点和备份节点组成的,但是,如果主节点作恶(比如主机点接收到了客户端的请求,但就是默不作声,不执行三阶段协议),那…

C脚本实现Wincc弹窗重复调用

文章目录 前言一、步骤及解析二、运行画面演示三、总结 前言 在常见的Wincc上位机画面中,点击按钮或控件弹出弹窗,由于不同的弹窗内容不同,变量前缀不同,通常情况下一个弹窗就需要调用一个画面窗口,但画面窗口过多会导…

Redis经典问题:数据不一致

大家好,我是小米,今天我想和大家聊一聊Redis的一个经典问题——数据不一致。在使用Redis的过程中,你是否曾遇到过这样的问题?缓存和数据库中的数据不一致,可能导致应用程序的功能异常。下面,我将详细介绍数据不一致的原因,以及一些有效的解决方案。 什么是数据不一致 …