多态

绑定: 将方法的调用与方法本身相联系叫“绑定”
            
        绑定分为前绑定与后绑定。前绑定是指绑定发生在程序运行之前。后绑定是指绑定发生在程序运行的时候,根据对象的类型来决定具体应该绑定哪个方法。后绑定也被称为“动态绑定”或者“运行时绑定”。除了 staticfinal方法,java的所有方法都是后绑定。也就是说所有的 static,final,private的方法都不能被覆写。

        这样做的好处是,实现多态的方法调用,我们就可以只关心同基类相关的部分。

例如

class  Shape  {
    
void draw();
    
void erase();
}


class  Circle  extends  Shape  {
    
void draw(){
        System.out.println(
"Circle.draw()");
    }

    
void erase(){
        System.out.println(
"Circle..erase()");
    }

}


class  Square  extends  Shape  {
    
void draw(){
        System.out.println(
"Square.draw()");
    }

    
void erase(){
        System.out.println(
"Square..erase()");
    }

}


class  Triangle  extends  Shape  {
    
void draw(){
        System.out.println(
"Triangle.draw()");
    }

    
void erase(){
        System.out.println(
"Triangle..erase()");
    }

}

       基类Shape为继承类定义了共用的接口(方法),派生类再覆写这些方法,提供自己特有的方法。

       当

Shape s  =   new  Circle();

        程序运行时自己知道应该调用 Circle的方法。

        然而这样做的话,又会带来一些问题。因为基类Shape只是做了定义,却没有真正的去实现。所以当调用基类的方法时,就会报错。解决的办法就是使用抽象类和抽象方法来阻止对基类方法的调用。如果继承了抽象类,并且打算创建一个新类的对象,那么就必须实现抽象类(基类)的全部抽象方法。上面的例子可以变为:

abstract   class  Sharp  {
    
public abstract void draw();
    
public abstract void erase();
}


class  Circle  extends  Shape  {
    
void draw(){
        System.out.println(
"Circle.draw()");
    }

    
void erase(){
        System.out.println(
"Circle..erase()");
    }

}


class  Square  extends  Shape  {
    
void draw(){
        System.out.println(
"Square.draw()");
    }

    
void erase(){
        System.out.println(
"Square..erase()");
    }

}


class  Triangle  extends  Shape  {
    
void draw(){
        System.out.println(
"Triangle.draw()");
    }

    
void erase(){
        System.out.println(
"Triangle..erase()");
    }

}

构造函数的调用顺序

   
     1,调用基类的构造函数,这是一个递归,也就是由最原始的父类开始调用
        2,成员对象按照声明的顺序进行初始化
        3,执行继承类自身的构造函数
        其中有一个问题:如果构造函数调用了一个动态绑定的方法,而且这个方法属于那个正在创建的对象,那么构造函数应该怎么做?


abstract   class  Shape  {
    
abstract void draw();

    Shape()
{
        System.out.println(
"Shape() before draw()");
        draw();
        System.out.println(
"Sharp() after draw()");
    }

}


class  Circle  extends  Shape  {
    
private int radius = 1;
    Circle(
int r){
        radius 
= r;
        System.out.println(
"Circle.Circle(), radius = "+ radius);
    }

    
void draw(){
        System.out.println(
"Circle.draw(), radius = " + radius);
    }


}


public   class  Sharp {
    
public static void main(String[] args){
        
new Circle(5);
    }

}

得到的结果为:

Shape() before draw()
Circle.draw(), radius = 0
Sharp() after draw()
Circle.Circle(), radius = 5

        所以开始说的调用顺序应当改为:
        1,对象初始化为0
        2,调用基类的构造函数,这是一个递归,也就是由最原始的父类开始调用。调用的同时会调用被覆写的方法。
        3,成员对象按照声明的顺序进行初始化
        4,执行继承类自身的构造函数
        但是这样会带来许多意想不到的bug。所以一个好的构造函数应当是它只能调用final的方法,因为final的方法不能覆写。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值