什么是多态
多态调用表现为:表面看起来你对父类调用了一个方法,实际上在方法的响应过程中由子类(方法的接收者)根据自己是谁,自行决定要怎么去响应它。其中方法的接收者是xxx.f()中的xxx。
Shape shape = new Circle(1);
shape.getArea();
静态方法是没有多态的
参数是静态绑定的,接收者是动态绑定的。换句话说多态只对方法的接收者生效。又换句话说多态只选择接收者的类型,不选择参数的类型。
举个例子:如下代码,试想会输出什么结果?答案是:I am Sub, the param is ParamBase。参数的选择是由方法重载所决定的,选择的参数是最不用转换(匹配度最高)的那一个。
public class Base {
public void print(ParamBase param){
System.out.println("I am Base, the param is ParamBase");
}
public void print(ParamSub param){
System.out.println("I am Base, the param is ParamSub");
}
}
public class Sub extends Base {
@Override
public void print(ParamBase param) {
System.out.println("I am Sub, the param is ParamBase");
}
@Override
public void print(ParamSub param) {
System.out.println("I am Sub, the param is ParamSub");
}
}
public class Main {
public static void main(String[] args) {
Base obj = new Sub();
ParamBase param = new ParamSub();
obj.print(param);
}
}
再举一个实际的例子:HashSet.addAll方法。HashSet的addAll方法是从AbstractCollection中继承过来的,它本身没有重写。AbstractCollection有一个add方法,addAll方法又调用了add方法。Hashset重写了add方法。这可能听起来有点绕,我们用一张图说明清楚。问题是HashSet.addAll()这个语句调用的add方法是HashSet还是AbstractCollection的?答案是:Hashset。
总结一下:多态的意思是根据当前的类型决定调用哪个方法。任何时候实例方法的选择,都是由当前对象根据自己实际的类型来决定去调用哪个方法的。
多态实战:策略模式
使用策略模式重构这个方法,实现三个策略:
NoDiscountStrategy 不打折
Discount95Strategy 全场95折
OnlyVipDiscountStrategy 只有VIP打95折,其他人保持原价
public class PriceCalculator {
public static int calculatePrice(DiscountStrategy strategy, int price, User user){
// 这里体现了多态的思想。
return strategy.discount(price, user);
}
}
public class DiscountStrategy {
public int discount(int price, User user) {
throw new UnsupportedOperationException();
}
}
public class NoDiscountStrategy extends DiscountStrategy {
@Override
public int discount(int price, User user) {
return price;
}
}
public class Discount95Strategy extends DiscountStrategy {
@Override
public int discount(int price, User user) {
return (int)(price * 0.95);
}
}
public class OnlyVipDiscountStrategy extends DiscountStrategy {
@Override
public int discount(int price, User user) {
if (user.isVip()) {
return (int) (price * 0.95);
} else {
return price;
}
}
}
再举一个JDK中线程池ThreadPoolExecutor的例子:其中几个个构造器中有RejectedExecutionHandler这样一个参数,这个参数就是一种策略模式。
分别有以下几种策略: