一 学习core java时,讲了多态与动态绑定过程
该文内容为本人学习Java核心编程第七版时做的学习总结以及一些理解,部分内容为翻译过来的。
http://dev.csdn.net/author/CMTobby/c902344dd80a47fdac8d0928ea1a3dd5.html
1. 多态(polymorphism)
在面向对象的编程里面,多态是一个出现频率比较高的术语,那么多态到底是指什么
呢?一个对象变量(object variable,与基本数据类型的变量相对应)可以指向(refer to)多个类型的对象,这就是多态。以下面的代码为例:
public class PolymorphicTest {
public PolymorphicTest() {
}
public void setName(String n){
this.name=n;
System.out.println(“在父类中”);
}
public String getName(){
return this.name;
}
private String name;
}
public class PolymorphicChild extends PolymorphicTest {
public void setArea(String a){
this.area=a;
}
public String getArea(){
return this.area;
}
//public void setName(String n){
// super(“n”);
// System.out.pirngln(“在子类中”);
// }
public static void main(String[] args) {
PolymorphicChild child=new PolymorphicChild();
PolymorphicTest test[]=new PolymorphicTest[2];
test[0]=child;
test[0].setName(“zhukai”);
test[1]=new PolymorphicTest();
}
private String area;
}
test[0]声明为一个PolymorphicTest的变量,但是它可以refer to一个PolymorphicChild类型的对象(如child),当然它也肯定可以refer to一个PolymorphicTest类型的对象,因为它本身就是这个类型的,例如test[1]。为什么会这样呢?一般来说,一个对象变量可以指向(refer to)任意一个它自己所属类型及其子类型的对象,有一个有名的(is-a)规则,类似于我国古代的“白马非马”这个典故。它就是说,任何一个子类的对象都可以说成是其父类的一个对象,但是反之则不一定了,例如,我们可以说白马是马,但是不能说马是白马。这个规则的另外一个表示方法就是“替换”准则:凡是程序中需要用到父类对象的地方,我们都可以用其子类的对象来进行替换。
接下来,就产生了一个问题,我们调用test[0]的setName(String n)方法的时候,它调用的到底是PolymorphicTest类还是PolymorphicChild类的setName方法呢?这就涉及到动态绑定的问题了,对象如何自动的选择合适的方法来执行?
2. 动态绑定(Dynamic Binding)
以上一节中的test[0].setName(String n)为例,我们现在有语句test[0].setName(“zhukai”),
那么它的执行过程是什么样的呢?
第一步:查看test[0]声明的类型,即PolymorphicTest类,然后获得方法名setName,接着把PolymorphicTest类中的所有名字为setName的方法以及其父类中所有名字为setName的public方法列出来。若没有名为setName的方法,则调用失败,否则转第二步。
第二步:根据所调用方法的参数类型来对上一步所列出来的所有方法进行匹配,直到找到一个匹配的转第三步,如果没有匹配则调用失败。
第三步:若test[0]所指向(refer to)的对象的类型为其一个子类,则需查看子类有没有覆盖该方法,若有,则执行子类中的方法。
注1:如果这个方法是private或者static或者final类型的,就不用进行动态绑定了,因为编译器可以很准确的知道要调用哪个方法。
注2:查询匹配方法时,是按照继承树逐级向上查找,直到找到第一个匹配的。
以上就是动态绑定的过程。
以上面的程序为例,程序执行时,当执行test[0].setName(“zhukai”)时,将会输出“在父类中”,如果去掉PolymorphicChild中的注释,此时将会先输出“在父类中”,然后再输出“在子类中”。
二 理解JAVA多态
这几天我在重新复习Java语言基础,虽然和团队一起,自己个人都进行了实际项目的开发,但越往上面走越觉得自己应该花点时间看看Java的基础知识,巩固一下基础。今天复习的是多态,同时写下自己的学习心得。
数据抽象、继承和多态是面向对象程序设计语言的三大特性。多态,我觉得它的作用就是用来将接口和实现分离开,改善代码的组织结构,增强代码的可读性。在某些很简单的情况下,或许我们不使用多态也能开发出满足我们需要的程序,但大多数情况,如果没有多态,就会觉得代码极其难以维护。
在Java中,谈论多态就是在讨论方法调用的绑定,绑定就是将一个方法调用同一个方法主体关联起来。在C语言中,方法(在C中称为函数)的绑定是由编译器来实现的,在英文中称为early binding(前期绑定),因此,大家自然就会想到相对应的late binding(后期绑定),这在Java中通常叫做run-time binding(运行时绑定),我个人觉得这样称呼更贴切,运行时绑定的目的就是在代码运行的时候能够判断对象的类型。通过一个简单的例子说明:
/**
* 定义一个基类
*/
public Class Parents {
public void print() {
System.out.println(“parents”);
}
}
/**
* 定义两个派生类
*/
public Class Father extends Parents {
public void print() {
System.out.println(“father”);
}
}
public Class Mother extends Parents {
public void print() {
System.out.println(“mother”);
}
}
/**
* 测试输出结果的类
*/
public Class Test {
public void find(Parents p) {
p.print();
}
public static void main(String[] args) {
Test t = new Test();
Father f = new Father();
Mother m = new Mother();
t.find(f);
t.find(m);
}
}
最后的输出结果分别是father和mother,将派生类的引用传给基类的引用,然后调用重写方法,基类的引用之所以能够找到应该调用那个派生类的方法,就是因为程序在运行时进行了绑定。
学过Java基础的人都能很容易理解上面的代码和多态的原理,但是仍有一些关键的地方需要注意的,算是自己对多态的一个小结:
1. Java中除了static和final方法外,其他所有的方法都是运行时绑定的。在我另外一篇文章中说到private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中static、final、或private方法时,实质上是创建了一个新的方法。
2.在派生类中,对于基类中的private方法,最好采用不同的名字。
3.包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。
4.对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。
5.在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。
6.构造方法是被隐式声明为static方法。
7.用继承表达行为间的差异,用字段表达状态上的变化。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1627040
三 java多态性最精辟解释
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1744969
对于java语音的多态性,看起来比较复杂,一般书大篇的介绍,不精简。
在这里,我将书上看到的总结如下:(只要牢记如下三天规则就ok)
1.实例方法与引用变量实际引用的对象的方法绑定,这种绑定属于动态绑定,
2.静态方法与引用变量所声明的类型的方法绑定,这种绑定属于静态绑定,
3.成员变量(包括静态成员变量和实例变量)与引用变量所声明的类型的成员变量绑定,这种绑定属于静态绑定。
class Base{
String var = "Base var";
static String staticVar="static var";
void method(){
System.out.println("base method");
}
static void staticMethod(){
System.out.println("base static method");
}
}
public class Sub exends Base{
String var ="Sub var"; //实例变量
static String staticVar="static Sub Var"; //静态变量
void method(){ //实例方法
System.out.println("sub method");
}
static void staticMethod(){
System.out.println("sub static method");
}
Base who=new Sub(); //who被声明为base类型,引用sub实例
System.out.println(who.var); //打印base类的var变量(第三条规则)
System.out.println(who.staticVar); //打印base类的staticvar变量(第三条规则)
who.method(); //调用sub实例的method方法(第一条规则)
who.staticmethod(); //调用base实例的staitcmethod方法(第二条规则)
}
我在本机运行的截图.