通过一个小Demo,来学习下向下转型,了解下这种特性的意义和使用场景。
新建一个饼干接口
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,可以看出,我们有的时候需要的各种类型的类,但是我们又想把它放在一个集合中,而不是每种类型都给一个集合存放,那样就太浪费资源了。这就需要使用向下转型,向上转型来进行编写代码。把很多种类的子类实例对象全部放入到存放父类实例的集合中。放入时,使用向上转型,子类实例赋值给父类引用,这样,完成向上转型后,子类丢失了自己独特的方法,然后通过向下转型的特性,将父类引用强转为子类实例对象。这样,子类又重新拥有了自己的独特的方法。