《Java编程思想》读书笔记——多态、动态绑定

一、什么是多态,什么是动态绑定

在面向对象程序设计中,多态是继数据抽象和继承之后的第三种基本特征
多态通过做什么怎么做,从另一角度将接口和实现分开。多态不但能够改善代码的组织结构和可读性,还能够创建可扩展的程序。
多态也称作动态绑定、后期绑定或运行时绑定

下面,我们通过一个例子来具体示范一下所谓的多态:

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

public class Cicle extends Shape{
    @Override
    public void draw(){
        System.out.println("Cicle draw");
    }
}

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

public class Test {
    public static void main(String[] args) {
        Shape c = new Cicle();
        Shape t = new Triangle();
        c.draw();
        t.draw();
    }
}

运行结果:
Cicle draw
Triangle draw

这里,创建了一个Cicle对象和一个Triangle对象,并分别把得到的引用赋值给两个Shape。这两个引用调用了draw()方法。根据运行结果可以看出明,两个Shape对象的引用,并没有调用Shape对象的draw()方法,而是调用了其指向对象的draw()方法。这就是动态绑定,编译器在运行时根据对象的类型进行绑定。
Java中除了static方法和final方法(private方法属于final方法)之外,其他所有的方法都是动态绑定。这意味着通常情况下,我们不必判定是否应该进行后期绑定——它会自动发生。

二、为什么要动态绑定

1、产生正确的行为

一旦知道了Java中所有方法都是通过动态绑定实现的多态这个事实,我们就可以编写只与基类打交道的程序代码了,并且这些代码对所有的导出类都可以正确运行。或者换一种说法,发送消息给某个对象,让该对象判定应该做什么事。

2、可扩展性

三、多态的缺陷

1、“覆盖私有方法”

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

public class Derived extends PrivateOverrite {
	public void f() {
		System.out.println("public f()");
	}
}
输出结果:
private f()

在导出类中,我们添加了一个与基类中一个私有方法同名的方法,再用基类引用指向导出类对象。用引用调用f()方法,本期望输出public f(),实际上,却调用了基类的似有方法,输出了private f()

结论就是:只有非private方法才可以被覆盖;但是还需密切注意private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行。确切地说,在导出类中,对与基类中的private方法,最好采用不同的名字。

2、域与静态方法

public class Super {
	public int field = 0;
	public int getField() {
		return field; 
	}
}
public 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);
		System.out.println("sup.getField() = " + sup.getField());
		Sub sub = new Sub();
		System.out.println("sub.field = " + sub.field);
		System.out.println("sub.getField() = " + sub.getField());
		System.out.println("sub.getSuperField() = " + sub.getSuperField());
	}
}

运行结果:
sup.field = 0
sup.getField() = 1
sub.field = 1
sub.getField() = 1
sub.getSuperField() = 0

咦,结果似乎有点不对劲,导出类引用指向基类对象再调用属性为什么会得到基类属性?答案就是:类中并非任何事物都可以多态地发生。

当Sub对象转型为Super引用时,任何域访问操作都将交由编译器解析,因此不是多态的。

你可能感兴趣的:(Java)