zoukankan      html  css  js  c++  java
  • 多态的理解

    多态很常识的理解就是向上转型,但是只记住这个概念会出错的,比如看下面的代码

    // polymorphism/PrivateOverride.java
    // Trying to override a private method
    // {java polymorphism.PrivateOverride}
    package polymorphism;
    
    public class PrivateOverride {
        private void f() {
            System.out.println("private f()");
        }
    
        public static void main(String[] args) {
            PrivateOverride po = new Derived();
            po.f();
        }
    }
    
    public Derived extends PrivateOverride {
        public void f() {
            System.out.println("public f()");
        }
    }

    private f()

    这里的private默认是final的,但是为什么你还能“重写”?因为你根本不是重写,你是在派生类扩展了一个方法,所以向上转型后只会调用基类的方法。

    针对这种情况,我们比较推荐加上@Ovrride注解,因为这样可以在编译的时候就报错让我们发现。

    error: method does not override or
    implement a method from a supertype

    多态还有一个陷阱就是属性与静态方法

    package Test;
    
    // polymorphism/FieldAccess.java
    // Direct field access is determined at compile time
    class Super {
        public int field = 0;
    
        public int getField() {
            return field;
        }
    }
    
    class Sub extends Super {
        public int field = 1;
    
        @Override
        public int getField() {
            return field;
        }
    
        public int getSuperField() {
            return super.field;
        }
    }
    
    public class FieldAccess {
        public static void main(String[] args) {
            Super sup = new Sub(); // Upcast
            System.out.println("sup.field = " + sup.field +
                    ", sup.getField() = " + sup.getField());
            Sub sub = new Sub();
            System.out.println("sub.field = " + sub.field +
                    ", sub.getField() = " + sub.getField()
                    + ", sub.getSuperField() = " + sub.getSuperField());
        }
    }

    sup.field = 0, sup.getField() = 1
    sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0

    当 Sub 对象向上转型为 Super 引用时,任何属性访问都被编译器解析,因此不是多态的。在这个例子中,Super.field 和 Sub.field 被分配了不同的存储空间,因此,Sub 实际上包含了两个称为 field 的属性:它自己的和来自 Super 的。然而,在引用 Sub 的 field 时,默认的 field 属性并不是 Super 版本的 field 属性。为了获取 Super 的 field 属性,需要显式地指明 super.field。

    // polymorphism/StaticPolymorphism.java
    // static methods are not polymorphic
    class StaticSuper {
        public static String staticGet() {
            return "Base staticGet()";
        }
    
        public String dynamicGet() {
            return "Base dynamicGet()";
        }
    }
    
    class StaticSub extends StaticSuper {
        public static String staticGet() {
            return "Derived staticGet()";
        }
        @Override
        public String dynamicGet() {
            return "Derived dynamicGet()";
        }
    }
    
    public class StaticPolymorphism {
        public static void main(String[] args) {
            StaticSuper sup = new StaticSub(); // Upcast
            System.out.println(StaticSuper.staticGet());
            System.out.println(sup.dynamicGet());
        }
    }
    
    Base staticGet()
    Derived dynamicGet()

    静态它只与类相关,多态和它没关系。

    构造器具有多态性吗? 答案是否定的,构造器如何具备多态性啊,这个要从对象上理解。虽然宝马和奥迪都是车,但是车的配件不一样啊,构造器的作用就是将制造这些配件也就是初始化变量。

    继承和清理

    // polymorphism/Frog.java
    // Cleanup and inheritance
    // {java polymorphism.Frog}
    package polymorphism;
    
    class Characteristic {
        private String s;
    
        Characteristic(String s) {
            this.s = s;
            System.out.println("Creating Characteristic " + s);
        }
    
        protected void dispose() {
            System.out.println("disposing Characteristic " + s);
        }
    }
    
    class Description {
        private String s;
    
        Description(String s) {
            this.s = s;
            System.out.println("Creating Description " + s);
        }
    
        protected void dispose() {
            System.out.println("disposing Description " + s);
        }
    }
    
    class LivingCreature {
        private Characteristic p = new Characteristic("is alive");
        private Description t = new Description("Basic Living Creature");
    
        LivingCreature() {
            System.out.println("LivingCreature()");
        }
    
        protected void dispose() {
            System.out.println("LivingCreature dispose");
            t.dispose();
            p.dispose();
        }
    }
    
    class Animal extends LivingCreature {
        private Characteristic p = new Characteristic("has heart");
        private Description t = new Description("Animal not Vegetable");
    
        Animal() {
            System.out.println("Animal()");
        }
    
        @Override
        protected void dispose() {
            System.out.println("Animal dispose");
            t.dispose();
            p.dispose();
            super.dispose();
        }
    }
    
    class Amphibian extends Animal {
        private Characteristic p = new Characteristic("can live in water");
        private Description t = new Description("Both water and land");
    
        Amphibian() {
            System.out.println("Amphibian()");
        }
    
        @Override
        protected void dispose() {
            System.out.println("Amphibian dispose");
            t.dispose();
            p.dispose();
            super.dispose();
        }
    }
    
    public class Frog extends Amphibian {
        private Characteristic p = new Characteristic("Croaks");
        private Description t = new Description("Eats Bugs");
    
        public Frog() {
            System.out.println("Frog()");
        }
    
        @Override
        protected void dispose() {
            System.out.println("Frog dispose");
            t.dispose();
            p.dispose();
            super.dispose();
        }
    
        public static void main(String[] args) {
            Frog frog = new Frog();
            System.out.println("Bye!");
            frog.dispose();
        }
    }
    Creating Characteristic is alive
    Creating Description Basic Living Creature
    LivingCreature()
    Creating Characteristiv has heart
    Creating Description Animal not Vegetable
    Animal()
    Creating Characteristic can live in water
    Creating Description Both water and land
    Amphibian()
    Creating Characteristic Croaks
    Creating Description Eats Bugs
    Frog()
    Bye!
    Frog dispose
    disposing Description Eats Bugs
    disposing Characteristic Croaks
    Amphibian dispose
    disposing Description Both wanter and land
    disposing Characteristic can live in water
    Animal dispose
    disposing Description Animal not Vegetable
    disposing Characteristic has heart
    LivingCreature dispose
    disposing Description Basic Living Creature
    disposing Characteristic is alive

    初始化的时候从上到下,清理的时候从下到上,一定要手动super调用基类的dispose()

    构造器内部的多态行为

    // polymorphism/PolyConstructors.java
    // Constructors and polymorphism
    // don't produce what you might expect
    class Glyph {
        void draw() {
            System.out.println("Glyph.draw()");
        }
    
        Glyph() {
            System.out.println("Glyph() before draw()");
            draw();
            System.out.println("Glyph() after draw()");
        }
    }
    
    class RoundGlyph extends Glyph {
        private int radius = 1;
    
        RoundGlyph(int r) {
            radius = r;
            System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
        }
    
        @Override
        void draw() {
            System.out.println("RoundGlyph.draw(), radius = " + radius);
        }
    }
    
    public class PolyConstructors {
        public static void main(String[] args) {
            new RoundGlyph(5);
        }
    }
    Glyph() before draw()
    RoundGlyph.draw(), radius = 0
    Glyph() after draw()
    RoundGlyph.RoundGlyph(), radius = 5
    1. 在所有事发生前,分配给对象的存储空间会被初始化为二进制 0。
    2. 如前所述调用基类构造器。此时调用重写后的 draw() 方法(是的,在调用 RoundGraph 构造器之前调用),由步骤 1 可知,radius 的值为 0。
    3. 按声明顺序初始化成员。
    4. 最终调用派生类的构造器。

    因此,编写构造器有一条良好规范:做尽量少的事让对象进入良好状态。如果有可能的话,尽量不要调用类中的任何方法。在构造器中唯一能安全调用的只有基类的 final 方法(包括 private 方法,它们自动属于 final)。这些方法不能被重写,因此不会产生意想不到的结果。你可能无法永远遵循这条规范,但应该朝着它努力。

    协变类型,怎么讲,容易误解,感觉没什么实际用处

    // polymorphism/CovariantReturn.java
    class Grain {
        @Override
        public String toString() {
            return "Grain";
        }
    }
    
    class Wheat extends Grain {
        @Override
        public String toString() {
            return "Wheat";
        }
    }
    
    class Mill {
        Grain process() {
            return new Grain();
        }
    }
    
    class WheatMill extends Mill {
        @Override
        Wheat process() {
            return new Wheat();
        }
    }
    
    public class CovariantReturn {
        public static void main(String[] args) {
            Mill m = new Mill();
            Grain g = m.process();
            System.out.println(g);
            m = new WheatMill();
            g = m.process();
            System.out.println(g);
        }
    }
    Grain
    Wheat

    这也是多态一种表现

    利用多态和继承我们可以实现一种状态模式

    // polymorphism/Transmogrify.java
    // Dynamically changing the behavior of an object
    // via composition (the "State" design pattern)
    class Actor {
        public void act() {}
    }
    
    class HappyActor extends Actor {
        @Override
        public void act() {
            System.out.println("HappyActor");
        }
    }
    
    class SadActor extends Actor {
        @Override
        public void act() {
            System.out.println("SadActor");
        }
    }
    
    class Stage {
        private Actor actor = new HappyActor();
    
        public void change() {
            actor = new SadActor();
        }
    
        public void performPlay() {
            actor.act();
        }
    }
    
    public class Transmogrify {
        public static void main(String[] args) {
            Stage stage = new Stage();
            stage.performPlay();
            stage.change();
            stage.performPlay();
        }
    }
    HappyActor
    SadActor

    向下转型也是可以的,不过需要强转,并且很容易出错,基本不用。

    // polymorphism/RTTI.java
    // Downcasting & Runtime type information (RTTI)
    // {ThrowsException}
    class Useful {
        public void f() {}
        public void g() {}
    }
    
    class MoreUseful extends Useful {
        @Override
        public void f() {}
        @Override
        public void g() {}
        public void u() {}
        public void v() {}
        public void w() {}
    }
    
    public class RTTI {
        public static void main(String[] args) {
            Useful[] x = {
                new Useful(),
                new MoreUseful()
            };
            x[0].f();
            x[1].g();
            // Compile time: method not found in Useful:
            //- x[1].u();
            ((MoreUseful) x[1]).u(); // Downcast/RTTI
            ((MoreUseful) x[0]).u(); // Exception thrown
        }
    }

    编译和运行都会让你拒绝向下转型。

    一个没有高级趣味的人。 email:hushui502@gmail.com
  • 相关阅读:
    ab 性能测试工具的使用(Web并发测试)
    java 读取文件——按照行取出(使用BufferedReader和一次将数据保存到内存两种实现方式)
    java 判断两个时间相差的天数
    java 正则表达式的应用:读取文件,获取其中的电话号码
    mybatis 插入数据时返回主键
    CodeForces 493B Vasya and Wrestling 【模拟】
    图像边缘检測小结
    【JS设计模式】温习简单工厂模式、工厂方法模式、抽象工厂模式概念
    60.自己定义View练习(五)高仿小米时钟
    bzoj4361 isn
  • 原文地址:https://www.cnblogs.com/CherryTab/p/11931309.html
Copyright © 2011-2022 走看看