美文网首页Java 之旅
初级09 - 面向对象:多态

初级09 - 面向对象:多态

作者: 晓风残月1994 | 来源:发表于2019-08-03 15:55 被阅读0次

    面向对象的三大基本原则之一 ——多态。多态赋予了你的程序无与伦比的强大功能,是面向对象的灵魂!


    面向对象的三大特征:

    • 封装
    • 继承
    • 多态

    1. 什么是多态?

    这不是多态:

    Person p1 = new Person();
    

    下面是多态!Man 和 Woman 都是 Person 的子类:

    Person p2 = new Man();
    Person p3 = new Woman();
    

    这就体现了对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
    也因为一个子类类型的对象永远也是一个父类类型的对象,因此,当声明一个父类型时,总可以传递一个子类型对象。

    多态性可以理解为一个事务的多种形态,= 赋值的右边有多种形态的对象来满足左边的需求。

    2. 多态的使用

    有了对象的多态性以后,在编译期,只能调用父类中声明的方法,但在运行期,实际执行的是子类重写父类后的方法。

    • 实例方法默认是多态的,在运行时根据this来决定调用哪个方法,而静态方法没有多态;
    • 参数是静态绑定,接收者是动态绑定;
    • 多态只对方法的接收者生效;
    • 多态只选择接收者的类型, 不选择参数的类型;
    • 例如:HashSet.addAll()
    • 静态方法的调用是通过在编译器静态绑定的,而实例方法的调用是在运行时动态绑定的
    • 多态是运行时行为

    假设子类分别覆盖了父类的eat()walk()

    Person p2 = new Man();
    p2.eat();
    p2.walk();
    

    那么上面这样写是ok的,在编译期,这两个方法指的仍是父类Person的实例方法,运行时,子类对象接收到了方法调用的消息(同时可能还有方法的参数),其作为接收者要进行响应,发现子类进行了重写,于是动态调用重写后的方法。

    接着这个思路,如果对p2调用只有子类Man中才存在的实例方法,在编译阶段会报错,因为编译时认为p2 属于赋值操作左边的类型,认为是Person类型,而Person并没有定义站着尿尿这个方法。

    p2.站着尿尿();
    

    结论

    • 编译时,看左边;运行时,看右边。
    • 多态的使用前提:
      • 类的继承关系
      • 方法的重写

    3. 虚拟方法调用(多态的情况下)

    子类中重写了父类方法后,在多态情况下,将此时父类的方法称为虚拟方法,在运行时,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的,所以比较虚。

    在编译时是父类类型,运行时成了对子类类型上的方法调用,这个过程也称为动态绑定

    借用一张尚硅谷免费资源中的PPT:


    多态

    4. 设计模式实战:策略模式

    策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

    使用了工厂方法的User(注意这个类不是策略模式必须的,或者说无关):

        private String name;
        private boolean vip;
    
        private User(String name, boolean vip) {
            this.name = name;
            this.vip = vip;
        }
    
        public static User vip(String name) {
            return new User(name, true);
        }
    
        public static User dios(String name) {
            return new User(name, false);
        }
    
        public String getName() { return name; }
    
        public boolean isVip() { return vip; }
    }
    

    接下来属于策略模式。

    一个需要调用这组算法策略的使用者PriceCalculator

    public class PriceCalculator {
        // 使用策略模式实现三个策略:
        // NoDiscountStrategy 不打折
        // Discount95Strategy 全场95折
        // OnlyVipDiscountStrategy 只有VIP打95折,其他人保持原价
    
        public static int calculatePrice(DiscountStrategy strategy, int price, User user) {
             return strategy.discount(price, user); // 实际执行的是子类重写后的方法
        }
    
        public static void main(String[] args) {
            User user = User.dios("wangpeng");
            System.out.println("用户名:" + user.getName());
            // 使用什么策略就传入什么策略
            int price = calculatePrice(new Discount95Strategy(), 10000, user);
            System.out.println("实际价格:" + price);
        }
    }
    

    策略的父类DiscountStrategy

    public class DiscountStrategy {
        // 虽然正常情况下这个基类中的策略都会被某个具体策略给Override,但我认为目的有二:
        // 1. 被子类覆盖从而实现多态调用
        // 2. 用来兜底,抛出个异常
        public int discount(int price, User user) {
            throw new UnsupportedOperationException();
        }
    }
    

    没有折扣的NoDiscountStrategy

    public class NoDiscountStrategy extends DiscountStrategy {
        @Override
        public int discount(int price, User user) {
            return price;
        }
    }
    

    打95折的Discount95Strategy

    public class Discount95Strategy extends DiscountStrategy {
        @Override
        public int discount(int price, User user) {
            return (int)(price * 0.95);
        }
    }
    

    Vip独享的打折策略OnlyVipDiscountStrategy

    public class OnlyVipDiscountStrategy extends DiscountStrategy {
        @Override
        public int discount(int price, User user) {
            if (user.isVip()) {
                return (int) (price * 0.95);
            } else {
                return price;
            }
        }
    }
    

    策略模式和模板方法模式有些类似,二者的界限在于:父类中是否包含“骨架”逻辑

    策略模式的父类中几乎没有代码(大多数情况是个抽象方法),但是模版方法模式的父类中有一个“模板方法”,包含很多“骨架”逻辑代码。


    参考文章:
    Java中为什么静态方法不能被重写?为什么静态方法不能隐藏实例方法?

    相关文章

      网友评论

        本文标题:初级09 - 面向对象:多态

        本文链接:https://www.haomeiwen.com/subject/maocdctx.html