Java SE5中添加协变返回类型,表示在导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型。
如现有:导出类WheatMill,被覆盖方法process(),基类Mill,基类方法的返回类型Grain,其导出类型Wheat。
基类Mill
/**
* 磨坊; 工厂; 磨粉机; 榨汁机;
*/
public class Mill {
Grain process(){
return new Grain();
}
}
基类方法的返回类型Grain
/**
* 谷物(Grain ),可以在工厂(Mill)中被加工(process)
*/
public class Grain {
private String name;
@Override
public String toString() {
return "Grain{}---谷物";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
基类Mill的导出类WheatMill
/**
* 工厂/磨坊(Mill)的导出类小麦磨坊(Mill)
*
*/
public class WheatMill extends Mill {
/**
* 重写Mill的process()方法
* 协变返回类型允许返回更具体的Wheat类型,亦即此时的Wheat为协变返回类型
* @return
*/
Wheat process(){
return new Wheat();
}
}
基类Mill的导出类WheatMill
/**
* 谷物(Grain)的导出类小麦(Wheat)
*/
public class Wheat extends Grain{
private String color;
@Override
public String toString() {
return "Wheat{}---小麦: " + getName() + " , the color :"+ this.color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
测试类CovariantReturnDemo
/**
*By windcoder.com
*/
public class CovariantReturnDemo {
public static void main(String[] args) {
// 创建基类Mill的实例m
Mill m = new Mill();
// 获取m的返回类型Grain的实例g
Grain g = m.process();
//设置g的名称并打印
g.setName("windCoder.com");
System.out.println(g);
System.out.println(g.getName());
//将m重新分配给其类型(基类Mill)的导出类(WheatMill),由于m自身是Mill,此时自动向上转型
m = new WheatMill();
//获取m的返回类型Grain的实例g
g =m.process();
g.setName("bulu");
//! g.setColor("red"); //---此时g的类型依旧是基类Grain,故不存在其子类(Wheat)中的setColor()方法
System.out.println(g);
System.out.println(g.getName());
// 因为是协变返回类型,所以可以向下转型
Wheat w = (Wheat) g;
w.setColor("red");
System.out.println(g);
}
}
Grain{}---谷物: heihei
heihei
Wheat{}---小麦: bulu , the color :null
bulu
Wheat{}---小麦: bulu , the color :red
较早版本将强制process()的覆盖版必须返回Grain,而不能返回Wheat。
但Wheat是从Grain导出的,因而也应该是一种合法的返回类型。
协变返回类型允许返回更具体的Wheat类型
里氏代换原则(任何基类可以出现的地方,子类一定可以出现)
可见此处demo中WheatMill对Mill的process()方法的重写违反了重写规则3,但Wheat属于Grain的子类(即Wheat IS-A Grain),所以在向上的继承树转换时会隐式完成。此处的Wheat即成了协变返回类型。