多态,也叫动态绑定、后期绑定、运行时绑定,它通过分离做什么和怎么做,从另一个角度将接口和实现分开。
下面这段是在网上找到的!
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。 |
好长好复杂,下面以一段代码来说明!
class Instrument{
public void play(){
System.out.println("Instrument.play()!");
}
public void fuck(){
System.out.println("Instrument.fuck()!");
}
}
class Wind extends Instrument{
public void play(){
System.out.println("Wind.play()!");
}
}
class Brass extends Instrument{
public void lound(){
System.out.println("Brass.lound()!");
}
}
public class Music {
public static void main(String[] args){
Instrument wind1 = new Wind();
wind1.play();
wind1.fuck();
Wind wind2 = new Wind();
wind2.play();
wind2.fuck();
Brass brass1 = new Brass();
brass1.play();
brass1.lound();
}
}
运行结果如下:
Wind.play()!
Instrument.fuck()!
Wind.play()!
Instrument.fuck()!
Instrument.play()!
Brass.lound()!
将一个方法调用同一个方法主题关联起来被称为绑定,Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是后期绑定的。
从上的示例程序中,我们看到Wind类继承自Instrument类,并且重写了Instrument类中的方法,但是对于Brass类来说,虽然它继承自Instrument类,但是没有重写它的方法。对于它们来说,如果子类实现了父类的方法,那么不管这个实例对象是否有向上转型为父类,它都会调用子类中实现的方法,同时,如果子类没有实现父类的方法,它们的实例对象也可以调用父类的方法。不过,如果子类实现了父类没有的方法,对于向上转型的子类实例来说,它是无法调用的。
域与静态方法
class Super{
public int field = 0;
public int getField(){
return field;
}
}
class Sub extends Super{
public int field = 1;
public int getField(){return field;}
public int getSuperField(){
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args){
Super sup = new Sub();
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
从结果我们可以看到,对于域来说,并没有因为向上转型,而将域的值覆盖。也就是说,任何域访问操作都将由编译器解析,因此不是多态的。
所以当访问域的时候,声明为哪个域,不必要关心它是否向上转型,它实际调用的是就是它本身的域,如果想要调用父类的域,需要使用super方法!
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()!";
}
public String dynamicGet(){
return "Derived dynamicGet()!";
}
}
public class StaticTest {
public static void main(String[] args){
StaticSuper sup = new StaticSub();
System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
}
运行结果如下:
Base staticGet()!
Derived dynamicGet()!
对于静态方法来说,它是与类相关联的。所以在向上转型之后,它会调用父类的方法!
构造器的调用顺序
<1>调用基类构造器,这个步骤会反复的递归下去,直到最顶层被调用。
<2>按声明顺序调用成员的初始化方法。
<3>调用导出类构造器的主体。
class Meal{
Meal(){
System.out.println("Meal()");
}
}
class Bread{
Bread(){
System.out.println("Bread()");
}
}
class Cheese{
Cheese(){
System.out.println("Cheese()");
}
}
class Lunch extends Meal{
Lunch(){
System.out.println("Lunch()");
}
}
class subLunch extends Lunch{
subLunch(){
System.out.println("subLunch()");
}
}
public class Sandwich extends subLunch{
private Bread b = new Bread();
private Cheese c = new Cheese();
public Sandwich(){System.out.println("Sandwich()");}
public static void main(String[] args){
new Sandwich();
}
}
运行结果如下:
Meal()
Lunch()
subLunch()
Bread()
Cheese()
Sandwich()