一开始学习 Java 时不重视向下转型。一直搞不清楚向下转型的意义和用途,不清楚其实就是不会,那开发的过程肯定也想不到用向下转型。

其实向上转型和向下转型都是很重要的,可能我们平时见向上转型多一点,向上转型也比较好理解。 
但是向下转型,会不会觉得很傻,我是要用子类实例对象,先是生成子类实例赋值给父类引用,在将父类引用向下强转给子类引用,这不是多此一举吗?我不向上转型也不向下转型,直接用子类实例就行了。 
我开始学习Java时也是这么想的,这误区导致我觉得向下转型就是没用的。 
随着技术的提升,我在看开源的项目学习,发现很多地方都用了向下转型的技术,这就让我重视了起来,想要重新来复习(学习)这个知识点。也是搜索了许多博客文章,但都没具体说明向下转型,只是给了例子演示怎么使用,反而是向上转型讲了一堆(可能是我没找到)。

这篇博客就是讲向下转型的,那我们就来学习下向下转型,了解下这种特性的意义和使用场景

新建一个电子产品接口,如下:

public interface Electronics{

}

很简单,什么方法都没有。

新建一个Thinkpad笔记本类,并实现电子产品接口:

public class Thinkpad implements Electronics{

    //Thinkpad引导方法
public void boot(){
System.out.println("welcome,I am Thinkpad");
} //使用Thinkpad编程
public void program(){
System.out.println("using Thinkpad program");
} }

新建一个Mouse鼠标类,并实现电子产品接口:

public class Mouse implements Electronics{

    //鼠标移动
public void move(){
System.out.println("move the mouse");
} //鼠标点击
public void onClick(){
System.out.println("a click of the mouse");
} }

新建一个Keyboard键盘类,并实现电子产品接口:

public class Keyboard implements Electronics{

    //使用键盘输入
public void input(){
System.out.println("using Keyboard input");
} }

这里子类比较多,是为了更好的理解。每个类的方法的逻辑实现也很简单。打印了一行信息

接下来,我们想象一个情景:我们去商城买电子产品,电子产品很多吧,比如笔记本电脑,鼠标,键盘,步步高点读机哪里不会点哪里,我们用的手机,等等,这些都属于电子产品。电子产品是抽象的。好,那么我们决定买一台Thinkpad,一个鼠标和一个键盘。 
这时,我们需要一个购物车来装这些电子产品吧。我们可以添加进购物车,然后通过购物车还能知道存放的电子产品数量,能拿到对应的电子产品。 
那么,一个购物车类就出来了,如下:

import java.util.ArrayList;
import java.util.List; public class ShopCar{ private List<Electronics> mlist = new ArrayList<Electronics>(); public void add(Electronics electronics){ mlist.add(electronics); } public int getSize(){ return mlist.size();
} public Electronics getListItem(int position){ return mlist.get(position); } }

List 集合是用来存放电子产品的,add 方法用来添加电子产品到购物车,getSize 方法用来获取存放的电子产品数量,getListItem 方法用来获取相应的电子产品。

可以看到 List<Electronics> 用了泛型的知识,至于为什么要用泛型?这个不做介绍了,泛型很重要的。 
而我觉得比较疑惑的是为什么是放 Electronics 的泛型,而不是放Thinkpad,Mouse,Keyboard,Phone等? 
那么如果是List<Thinkpad>,肯定是放不进鼠标Mouse的吧,难道要生成3个集合?这里是定义了3个电子产品类,但是我如果有100种电子产品呢,要定义100个集合? 
这太可怕了。所以之前,我们写了一个Electronics接口,提供了一个Electronics的标准,然后让每一个Electronics子类都去实现这个接口。

实际上这里又涉及到了向上转型的知识点,我们虽然在add 方法将子类实例传了进来存放,但子类实例在传进去的过程中也进行了向上转型 
所以,此时购物车里存放的子类实例对象,由于向上转型成Electronics,已经丢失了子类独有的方法,以上述例子来分析,Thinkpad实例就是丢失了boot() 和program() 这两个方法,而Mouse实例就是丢失了move()和onClick()这两个方法

但是实际使用Thinkpad或Mouse或Keyboard时,这种情况肯定不是我们想要的

接着我们写一个测试类 Test 去测试购物车里的电子产品。

测试类 Test 如下:

public class Test{

    public static final int THINKPAD = 0;
public static final int MOUSE = 1;
public static final int KEYBOARD = 2; public static void main(String[] args){ //添加进购物车
ShopCar shopcar = new ShopCar();
shopcar.add(new Thinkpad());
shopcar.add(new Mouse());
shopcar.add(new Keyboard()); //获取大小
System.out.println("购物车存放的电子产品数量为 ——> "+shopcar.getSize()); //开始测试thinkpad电脑
Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);
thinkpad.boot();
thinkpad.program(); System.out.println("-------------------"); //开始测试Mouse鼠标
Mouse mouse = (Mouse)shopcar.getListItem(MOUSE);
mouse.move();
mouse.onClick(); System.out.println("-------------------"); //开始测试Keyboard键盘
Keyboard keyboard = (Keyboard)shopcar.getListItem(KEYBOARD);
keyboard.input();
} }

运行截图:

 

举个例子分析就好

//开始测试thinkpad电脑
Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);
thinkpad.boot();
thinkpad.program();

shopcar.getListItem(THINKPAD)这句代码是获取到Electronics类型的实例。不是Thinkpad的实例

通过向下转型,赋值给子类引用

Thinkpad thinkpad = (Thinkpad)shopcar.getListItem(THINKPAD);

这样子类实例又重新获得了因为向上转型而丢失的方法(boot 和program)

总结一下吧,很多时候,我们需要把很多种类的实例对象,全部扔到一个集合。(这句话很重要) 
在这个例子里就是把Thinkpad笔记本,Mouse鼠标,KeyBoard键盘等实例对象,全部扔到一个Shopcar购物车集合。 
但是肯定不可能给他们每个种类都用一个独立的集合去存放吧,这个时候我们应该寻找到一个标准,接口就是一个标准。这些都是各种电子产品,抽象成电子产品。然后一个Electronics接口就出来了。 
在回到刚才,我们把很多种类的实例对象全部扔到一个集合。或许这样比较好理解:把很多种类的子类实例对象全部扔到存放父类实例的集合。 
经过了这个过程,子类实例已经赋值给了父类引用(即完成了向上转型),但很遗憾的丢失了子类扩展的方法。 
很好的是Java语言有个向下转型的特性,让我们可以重新获得丢失的方法,即强转回子类 
所以我们需要用到子类实例的时候,就从那个父类集合里拿出来向下转型就可以了,一样可以使用子类实例对象

……

我在搜索java向下转型的意义时,得到一个比较好的答案是这样的: 
最大的用处是java的泛型编程,用处很大,Java的集合类都是这样的。

而在Android开发中,我们在Layout文件夹,用xml写的控件。为什么能在Activity等组件中通过 findViewById() 方法找到呢?为什么 findViewById(R.id.textview) 方法传入TextView的id后,还要转型为TextView呢?这就是 Java 向下转型的一个应用

Java向下转型的意义的更多相关文章

  1. Java 向下转型

    1.Java 中父类直接向子类转型的不合法的,可以编译但运行时报错. Java中子类直接向父类转型 是合法的,但转型后,可以执行的方法仅限存在于父类中的,在执行时,先看子类的是否有定义,有就执行,没有 ...

  2. Java学习笔记15---instanceof与向下转型

    感冒咳嗽停更了几天,今天恢复更新了. 先来看下instanceof与向下转型的概念: 1.instanceof instanceof是一个二元操作符,用法是:boolean result = a in ...

  3. 8.JAVA-向上转型、向下转型

    父子对象之间的转换分为了向上转型和向下转型,它们区别如下: 向上转型 : 通过子类对象(小范围)实例化父类对象(大范围),这种属于自动转换 向下转型 : 通过父类对象(大范围)实例化子类对象(小范围) ...

  4. 【JAVA】关于向上转型与向下转型

    向上转型: 子类引用的对象转换为父类类型称为向上转型.通俗地说就是是将子类对象转为父类对象.此处父类对象可以是接口 如果子类重写了父类的方法,就根据这个引用指向调用子类重写的这个方法,不是调用父类的, ...

  5. Java入门记(二):向上转型与向下转型

    在对Java学习的过程中,对于转型这种操作比较迷茫,特总结出了此文.例子参考了<Java编程思想>. 目录 几个同义词 向上转型与向下转型 例一:向上转型,调用指定的父类方法 例二:向上转 ...

  6. java 向上转型 向下转型

    //父类 四边形 class Quadrangle{ public static void draw (Quadrangle q){ } } //子类  public class Parallelog ...

  7. (转载)java多态(2)-------Java转型(向上或向下转型)

    5.13.1 向上转型 我们在现实中常常这样说:这个人会唱歌.在这里,我们并不关心这个人是黑人还是白人,是成人还是小孩,也就是说我们更倾向于使用抽象概念“人”.再例如,麻雀是鸟类的一种(鸟类的子类), ...

  8. Java中的向上转型和向下转型

    首先要明白一点向上转型和向下转型他们都是建立在继承的基础上. 一.向上转型 子类到父类的转换通常称作向上转型,通俗的说就是定义父类对象指向子类对象. 下面通过一个例子来深入理解向上转型. //定义一个 ...

  9. java基础值向上向下转型

    1.父类引用可以指向子类对象,子类引用不能指向父类对象. 2.向上转型:子类引用的对象转换为父类类型称为向上转型,把子类对象直接赋给父类引用叫upcasting,向上转型不用强制转型(类似于低精度赋给 ...

随机推荐

  1. UGUI ContentSizeFitter之Button根据Text自适应

    环境 Unity3D 5.3.6f1 练习地址:https://github.com/zhaoqingqing/UGUIDemo  布局放在Layout文件夹 文档:https://docs.unit ...

  2. Angular 开发小妙招1:提交表单数据验证不通过,更改输入组件的样式

    开发表单时,客户端数据完整性校验是必不可少的,在jquery 时代出现了无数的数据验证插件也很好用,开发Angular 应用时,angular 内置了一些常用的数据验证指令.今天要讲的不是这些指令如何 ...

  3. linux学习笔记整理(三)

    第四章 文件的基本管理和XFS文件系统备份恢复本节所讲内容:4.1 Linux系统目录结构和相对/绝对路径.4.2 创建/复制/删除文件,rm -rf / 意外事故4.3 查看文件内容的命令4.4 实 ...

  4. jar包内的文件导出的注意点

    1.截取文件名 windows 和linux 通用 String fp[] = filePath.replaceAll("\\\\","/").split(&q ...

  5. android与c#之间scoket获取数据进行赋值显示的问题

    Android端发送的信息为:“手机号码,低压,高压,心率”. 需要实时的将接收到的信息显示到“数据栏”中,但是在执行监听任务的时候,启用了一个主线程,在接收数据的时候直接将数值复制给文本框会出现错误 ...

  6. ubuntu18.04 pip换源 永久修改

    1. 创建pip.conf文件 cd ~/.pip 如果提示目录不存在的话,我们要自行创建一个,再进入目录 mkdir ~/.pip cd ~/.pip 在.pip目录下创建一个pip.conf文件 ...

  7. 解决不能再jupyter notebook中使用tensorflow

    在搭建cuda + Anaconda + tensorflow的开发环境时,在虚拟环境中的jupyter notebook启动后无法导入tensorflow.具体解决方案如下: 1.首先在虚拟环境中安 ...

  8. 1、话说linux内核

    1.内核和发行版的区别 到底什么是操作系统 linux.windows.android.ucos就是操作系统 操作系统本质上是一个程序,由很多个源文件构成,需要编译连接成操作系统程序(vmlinz.z ...

  9. SQL Server-聚焦事务、隔离级别详解(二十九)

    前言 事务一直以来是我最薄弱的环节,也是我打算重新学习SQL Server的出发点,关于SQL Server中事务将分为几节来进行阐述,Always to review the basics. 事务简 ...

  10. JSOUP如何POST只含JSON格式的数据

    引言 现在前后端分离渐渐成为主流,网站可以通过json格式的数据和服务端进行交互,比如下图: 关于这点,JSOUP官方API文档已经给出了解决方法 Connection requestBody​(St ...