java-多态

多态 后期绑定

    java中,除了static和final 方法,其他所有方法都是后期绑定的,先举一个多态的简单例子

class Instrument{
    public void play(){
        System.out.println("play instrument");
    }
}

class Piano extends Instrument{
    public void play(){
        System.out.println("play piano");
    }
}

class Volin extends Instrument{
    public void play(){
        System.out.println("play Volin");
    }
}

class Play_music{
    public static void paly_m(Instrument m){
        m.play();
    }
}

public class Main {

    public static void main(String[] args) throws InterruptedException {
        Instrument V = new Volin();
        Instrument P = new Piano();
        Play_music.paly_m(V);
        Play_music.paly_m(P);
    }
}

执行结果:


 要实现多态,子类中要重写基类中的方法,并且这个方法是public的,如果是private则不能实现

class Derived extends Main{
    public void f(){
        System.out.println("public f()");
    }
}

public class Main {
    private void f(){
        System.out.println("private f()");
    }
    public static void main(String[] args){
        Main p = new Derived();
        p.f();
    }
}

运行结果:


  可以发现,并没有实现多态。基类和子类中两个f()是两个不相关的,其实基类中的private方法,默认就是final,不能被重写。

基类的public方法都能被多态吗?

class StaticSuper{
    public static String staticGet(){
        return "Base staticGet";
    }

    public String dynamicGet(){
        return "Base dynamicGet";
    }
}

class StaticSub extends StaticSuper{
    public static String staticGet(){
        return "Sub staticGet";
    }

    public String dynamicGet(){
        return "sub dynamicGet";
    }
}

public class Main {

    public static void main(String[] args){
        StaticSuper sup = new StaticSub();
        System.out.println(sup.staticGet());
        System.out.println(sup.dynamicGet());
    }
}

运行结果:


   静态方法属于类,而并非与单个对象相关联,所以static是不能多态的

  方法能多态,那类中的域能多态吗?

class Super{
    public int filed = 0;
    public int getFiled(){
        return filed;
    }
}

class Sub extends Super{
    public int filed = 1;
    public int getFiled(){
        return filed;
    }
    public int getSuperField(){
        return super.filed;
    }
}

public class Main {

    public static void main(String[] args){
        Super sup = new Sub();
        System.out.println("sup.field=" + sup.filed +
                    ",sup.getFiled()=" + sup.getFiled());
        Sub sub = new Sub();
        System.out.println("sup.field=" + sub.filed +
                ",sup.getFiled()=" + sub.getFiled() +
                ",sup.getSuperField()=" + sub.getSuperField() );
    }
}

运行结果:

   这里为了演示,将域定义成了public,一般不这样做。可以看出,域并不能像方法那样能实现多态。

        我们知道如果要new一个子类对象,会先初始化基类中的变量和构造函数,如果基类中的构造函数调用了,多态中子类和基类都有的方法(即实现了多态),那会如何?

class Glyph{
    public void draw(){
        System.out.println("Glyph.draw()");
    }
    public Glyph(){
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glyph() after draw()");
    }
}

class RoundGlyph extends Glyph{
    private int radius = 1;
    public RoundGlyph(int r){
        radius = r;
        System.out.println("RoundGlyph.RoundGlyph(), radius=" + radius);
    }
    public void draw(){
        System.out.println("RoundGlyph.RoundGlyph(), radius=" + radius);
    }
}

public class Main {

    public static void main(String[] args){
        new RoundGlyph(5);
    }
}

运行结果:


 可以发现,基类中的构造方法竟然也执行了子类中的draw()方法,并且因为子类还未初始化,所以radius=0。要尽量避免这种情况发生,一旦出错,很难发现。

        在继承中,子类可以添加属于自己的方法,子类是基类的超集,如果通过向上转型来实现多态,要想调用子类中的自己新的方法,需要向下转型

class Userful{
    public void f(){};
    public void g(){};
}

class MoreUsefule extends Userful{
    public void f(){};
    public void g(){};
    public void u(){};
}

public class Main {

    public static void main(String[] args){
        Userful[] x = { new Userful(), new MoreUsefule()};
        x[0].f();
        x[1].g();

        //如果要调用子类中新方法,向下转型
        ((MoreUsefule)x[0]).u();      //出错啦 本身为Userful,没有u()方法
        ((MoreUsefule)x[1]).u();
    }
}

运行结果:


       出错了,Userful对象没有u()方法。当我使用的IDE编写时,并没有提醒出错,我也试了一下用javac 去编译文件,也没有报错,都是运行才出错,所以要多加小心。

最后,说一下协变返回类型:子类中的覆盖方法可以返回基类方法的返回类型的某种子类类型:

光看这个解释不太好懂,看个例子就会豁然开朗

class Grain{
    public String toString() {
        return "Grain";
    }
}

class Wheat extends Grain{
    public String toString(){
        return "Wheat";
    }
}

class Mill{
    Grain process(){
        return new Grain();
    }
}

class WheatWill extends Mill{
    Wheat process(){
        return new Wheat();
    }
}

public class Main {

    public static void main(String[] args){
        Mill m = new Mill();
        Grain g = m.process();
        System.out.println(g);

        m = new WheatWill();
        g = m.process();
        System.out.println(g);
    }
}

运行结果:


     相信聪明的你已经理解了。

总结:

    1.私有方法不能被多态,所以要想实现多态,子类应该重写基类的public方法

    2.域不能像方法那样多态

    3.static方法也不能实现多态

    4.尽量避免在基类构造方法中调用多态方法,如果调用了,多态会起作用,会调用子类中此方法,而此时子类还未初始化。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值