8.多态--java笔记

1.绑定

定义:将一个方法调用同一个方法主体关联起来称作绑定。

前期绑定 就是在程序运行之间就知道调用哪个主体的方法。

例子:Shape是基类

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

public class Circle extends Shape {
  public void draw() { print("Circle.draw()"); }
  public void erase() { print("Circle.erase()"); }
}

public class Triangle extends Shape {
  public void draw() { print("Triangle.draw()"); }
  public void erase() { print("Triangle.erase()"); }
}

---------
public void applyDraw(Shape shape){
      shape.draw();
}

applyDraw(new Circle());
此时shape.draw()在程序运行前不知道用哪个子类的draw。所以用后期绑定,后期绑定也是有某种类型信息在对象里面。

java中除了static和final(private方法也是final方法)其他方法都是后期绑定。static是静态,不和具体的对象实例联系。final是不想让其他覆盖,这是它第一个目的,还有就是在编译时直接插入到调用的位置,问题就是方法体长的效率反而低,所以使用final主要以第一个为选用标准。

2.覆盖私有方法的假象

public class PrivateOverride {
  private void f() { print("private f()"); }
  public static void main(String[] args) {
    PrivateOverride po = new Derived();
    po.f();
  }
}

class Derived extends PrivateOverride {
  public void f() { print("public f()"); }
} /* Output:
private f()
*///:~

因为private没有被覆盖,所以向上转型后使用的父类自己的f();

3.域和静态方法

public int field=0;

public static String method(){}

这两个在向上转型后都是使用父类的域和静态方法。 在此所有对域的访问通过编译器,也就是说在编译期间就能确定。静态方法只是与类连在一起,所以也是编译期间就可以确定.子类可以具有父类的可见(覆盖后)方法和域,总之,域和静态方法不具多态性。

只有普通方法的调用是多态的。

4.构造器和多态
构造器其实是隐式的static,不具备多态性,但是构造器的调用顺序还是要注意一下。
class Glyph {
  void draw() { print("Glyph.draw()"); }
  Glyph() {
    1.  print("Glyph() before draw()");
    draw();
    3.   print("Glyph() after draw()");
  }
}   

class RoundGlyph extends Glyph {
  private int radius = 1;
  RoundGlyph(int r) {
    radius = r;
 4.   print("RoundGlyph.RoundGlyph(), radius = " + radius);
  }
  void draw() {
   2.  print("RoundGlyph.draw(), radius = " + radius); 此时成员初始化还没执行,所以radius是0.
  }
}   
public class PolyConstructors {
  public static void main(String[] args) {
    new RoundGlyph(5);
  }
} /* Output:
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
*///:~

构造顺序
1.任何事物发生之前,分配给对象的存储空间初始化成二进制的零。这个第二步radius为0的原因。
2.基类成员then基类构造器。
3.重复2。
4.导出类的成员then构造器。


5.协变返回类型

直接说它的含义有点绕,下面通过例子说明一下
class Mill {
  Grain process() { return new Grain(); }
}

class WheatMill extends Mill {
  Wheat process() { return new Wheat(); }
}
Wheat是Grain的一个导出类。
注意此时process的返回类型不一样。
Mill m= new WheatMill();
m.process返回的是Wheat。这就是协变返回,导出类WheatMill中覆盖的方法process可以返回基类方法process返回类型Grain的某种导出类型Wheat。
核心:这里process是覆盖的,因为返回类型Grain是Wheat的基类,这个条件很重要。
6.纯继承和扩展
老问题了,纯继承是is-a的关系,扩展时is-like-a的关系。

7.向下转型成某个导出类都要进行类型检查



你可能感兴趣的:(java,F#)