通过一个小Demo,来学习下向下转型,了解下这种特性的意义和使用场景。
新建一个饼干接口,(对于接口不了解的小伙伴,可以阅读这篇文章Java编程——对于接口的理解)
package com.shenqi.xiaobaiyang; /* * 新建一个饼干接口 */ public interface Biscuits {}
新建一个曲奇饼干类,并实现饼干接口
package com.shenqi.xiaobaiyang; /* * 新建一个曲奇饼干类,并实现饼干接口 */ public class Cookies implements Biscuits { public String rawMaterialcookies() { return "曲奇饼干:以小麦粉、糖、乳制品为主要原料," + "加入疏松剂和其他辅料,以和面,采用挤注、挤条、" + "钢丝节割等方法中的一种形式成型,烘烤制成的具有立体花纹" + "或表面有规则波纹、含油脂高的酥化焙烤食品。"; } }
新建一个夹心饼干类,并实现饼干接口
package com.shenqi.xiaobaiyang; /* * 新建一个夹心饼干类,并实现饼干接口 */ public class SandwichBiscuit implements Biscuits { public String rawMaterialSandwichBiscuit() { return "夹心饼干:在两块饼干之间添加糖、" + "油脂或果酱为主要原料的各种夹心料的夹心焙烤食品。"; } }
新建一个酥性饼干类,并实现饼干接口
package com.shenqi.xiaobaiyang; /* * 新建一个酥性饼干类,并实现饼干接口 */ public class ShortBiscuit implements Biscuits { public String rawMaterialShortBiscuit() { return "酥性饼干,以小麦粉、糖、油脂为主要原料," + "加入疏松剂和其他辅料,经冷粉工艺调粉、辊压、辊印或者冲、" + "烘烤制成的造型多为凸花的,断面结构呈现多孔状组织,口感疏松的烘焙食品。"; } }
这里子类很多,但是里面只有一个方法,返回自己类型饼干的原料。
我一般在外面超市买饼干的时候,都会背个包去。那么,一个用来装东西的类就出来了。新建一个包类。
package com.shenqi.xiaobaiyang; import java.util.ArrayList; import java.util.List; /** * * @author xiaobaiyang * 功能:可以知道包中有多少盒饼干,可以拿出对应的饼干类型以供小白阳【这个吃货】享用。 * */ public class Bag { //饼干数量 private static int Size = 0; private List<Biscuits> mlist = new ArrayList<Biscuits>(); /** * 用于将类型饼干的实例添加到List集合中。 * * @param biscuits 向上转型——子类实例在传进去的过程中进行了向上转型 */ public void add(Biscuits biscuits){ mlist.add(biscuits); Size++; } /** * * @return 返回包中有多少盒饼干。 */ public int getSize(){ return Size; } /** * 通过item参数来获取相对应的饼干类型。 * * @param item 对应参数 * @return 返回与对应参数item相对应的类型饼干 */ public Biscuits getTypesOfBiscuits(int item){ Size--; return mlist.get(item); } }
包中的List集合存放类型饼干。add()方法用于将类型饼干添加到List集合中。并以向上转型的方式进行加入。使用泛型<Biscuits>,为什么要使用泛型<Biscuits>,而不是<Cookies>呢?那咱们反向思维一下,如果泛型放的是<Cookies>,那惨淡了呢,我的包里只能放入曲奇饼干,其他类型的饼干不能放入。编译期间不通过呀。那我只能吃曲奇饼干,这岂不是很惨的呢。只有一种口味的呢。所以,我绝对不允许这种情况的发生,嘿嘿,一开始我就写了一个Biscuits饼干接口,提供了一个Biscuits标准,然后让每一个Biscuits子类都去实现这个接口。这里就使用到向上转型的知识点,【向上转型】此时包中存放的子类实例对象,由于向上转型Biscuits,已经丢失了子类独有的方法,取上面的Cookies类来进行分析,Cookies类丢失了rawMaterialcookies()原料方法,但是如果我们使用Cookies类的时候,肯定不希望这种情况的方法。
下面我们写一个测试Test类。
package com.shenqi.xiaobaiyang; public class Test { public static final int Cookies = 0; public static final int SandwichBiscuit = 1; public static final int ShortBiscuit = 2; public static void main(String[] args) { // 从超市买完饼干后,将饼干放入包中 Bag bag = new Bag(); bag.add(new Cookies()); bag.add(new SandwichBiscuit()); bag.add(new ShortBiscuit()); //包中饼干数量 System.out.println("包中饼干数量:" + bag.getSize()); //开始享用曲奇饼干,查看它的原料 Cookies cookies = (com.shenqi.xiaobaiyang.Cookies) bag.getTypesOfBiscuits(Cookies); System.out.println("开始享用曲奇饼干。" + cookies.rawMaterialcookies()); //查看包中剩余饼干数量(盒) System.out.println("包中剩余饼干数量(盒):" + bag.getSize()); } }
测试结果如下:
包中饼干数量:3 开始享用曲奇饼干。曲奇饼干:以小麦粉、糖、乳制品为主要原料,加入疏松剂和其他辅料,以和面,采用挤注、挤条、钢丝节割等方法中的一种形式成型,烘烤制成的具有立体花纹或表面有规则波纹、含油脂高的酥化焙烤食品。 包中剩余饼干数量(盒):2
对上述代码进行分析:
//开始享用曲奇饼干,查看它的原料 Cookies cookies = (com.shenqi.xiaobaiyang.Cookies) bag.getTypesOfBiscuits(Cookies); System.out.println("开始享用曲奇饼干。" + cookies.rawMaterialcookies());
bag.getTypesOfBiscuits(Cookies)这句代码是获取到Biscuits类型的实例。不是Cookies的实例。
通过向下转型,赋值给子类引用
Cookies cookies = (com.shenqi.xiaobaiyang.Cookies) bag.getTypesOfBiscuits(Cookies); System.out.println("开始享用曲奇饼干。" + cookies.rawMaterialcookies());
这样子类实例又重新获得了因为向上转型而丢失的方法rawMaterialcookies()。
通过这个小Demo,可以看出,我们有的时候需要的各种类型的类,但是我们又想把它放在一个集合中,而不是每种类型都给一个集合存放,那样就太浪费资源了。这就需要使用向下转型,向上转型来进行编写代码。把很多种类的子类实例对象全部放入到存放父类实例的集合中。放入时,使用向上转型,子类实例赋值给父类引用,这样,完成向上转型后,子类丢失了自己独特的方法,然后通过向下转型的特性,将父类引用强转为子类实例对象。这样,子类又重新拥有了自己的独特的方法。