多态
对象既可以作为它自己本身的类型使用,也可以作为它的基类型使用
在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种特征
即:Music . tune() 方法接受一个Instrment 引用,同时也接受任何导出自Instrument的类,当然本身Music是子类,导出自Instrument类。
方法调用绑定
将一个方法调用同一个方法主体关联起来被称作绑定
包括:前期绑定 和 后期绑定(运行时根据对象的类型进行绑定,也成为动态绑定和运行时绑定)
Java中除了static方法和final方法(private方法属于final方法)之外,其他的所有方法都是后期绑定
声明final,可以“关闭”动态绑定,但是运用final要慎重。
产生正确的行为(向上转型)
package source.sunday;
import java.util.Random;
class Shape {
public void draw() {}
public void erase() {}
}
class Circle extends Shape {
public void draw() { System.out.println("Circle.draw()"); }
public void erase() { System.out.println("Circle.erase()"); }
}
class Square extends Shape {
public void draw() { System.out.println("Square.draw()"); }
public void erase() { System.out.println("Square.erase()"); }
}
class Triangle extends Shape {
public void draw() { System.out.println("Triangle.draw()"); }
public void erase() { System.out.println("Triangle.erase()"); }
}
class RandomShapeGenerator {
private Random rand = new Random();
public Shape next() {
switch(rand.nextInt(3)) {
case 0: return new Circle();
case 1: return new Square();
case 2: return new Triangle();
}
return null;
}
}
public class Shapes {
private static RandomShapeGenerator gen = new RandomShapeGenerator();
public static void main(String[] args) {
Shape[] s = new Shape[9];
for(int i = 0; i < s.length; i++)
s[i] = gen.next();
for(Shape shp : s)
shp.draw();
}
}
RandomShapeGenerator类似一个工厂,通过随机方式生成shape对象。
output:
域和静态方法,不存在多态:
假如父类和子类拥有相同名字的域,那么会分配两个不同的空间。实际上这种情况基本不存在,因为你通常会将所有的域声明为private,因此不能够直接访问,其次,你可能不会对基类的域与导出类的域赋予相同的名字的。
任何的域访问操作都是由编译器解析,因此不是多态的,如果直接访问域(域是public的情况,本身就很少见),会返回基类的域值。
如果某个方法是静态的,因为静态的方法是类的属性,所以它就不具有多态性。
package source.sunday;
class StaticSuper {
public static String staticGet() {
return "Base staticGet";
}
public String dynamicGet() {
return "Base dynamicGet";
}
}
class StaticBub extends StaticSuper {
public static String staticGet() {
return "Derived staticGet";
}
public String dynamicGet() {
return "Derived dynamicGet";
}
}
public class StaticPolymorphism {
public static void main(String[] args) {
StaticSuper ss = new StaticBub();
System.out.println(ss.staticGet());
System.out.println(ss.dynamicGet());
}
}
静态方法是与类,而并非与单个的对象相关联的。
output:
构造器的调用顺序:
1. 调用基类构造器。这个步骤会不断的反复递归下去,首先是构造这种层次结构的根,然后是下一层导出类,等等,直到最底层的导出类。
2. 按声明顺序调用成员的初始化方法。
3. 调用导出类构造器的主体。
注:构造器并不具有多态性,构造器实际上是static方法,只不过该static声明是隐式的。
向下转型
package source.sunday;
class Useful {
public void f() {}
public void g() {}
}
class MoreUseful extends Useful {
public void f() {}
public void g() {}
public void u() {}
public void v() {}
}
public class RTTI {
public static void main(String[] args) {
Useful[] x = {
new Useful(),
new MoreUseful()
};
x[0].f();
x[1].g();
((MoreUseful)x[1]).u();
((MoreUseful)x[0]).u(); //error:会抛出异常!没有此方法。
}
}
上述错误会抛出异常: java.lang.ClassCastException
Exception in thread "main" java.lang.ClassCastException: com.factory.action.Array cannot be cast to com.factory.action.ArrayExtend