首先申明一下,小弟初学Java,也许是有些地方还没学到吧,反正在这里有一个问题不太懂,希望各位不吝赐教!这是小弟发的第一个非回复的帖子,希望大家多多支持。
程序在Eclipse中编写,父类是Fahter,子类是Son,测试用的是TestOverLoad。三个类如下:public class Father {
    public Father() {   
        super();
           
    }   
    public void shout(Object word){   
        System.out.println("object father shout:"+word);  
    } 
    public void getSalary(int m){
     System.out.println("返回的值是:"+m);
    }}
public class Son extends Father {
    public Son(int m) {   
        super();
        bonus=m;
           
    }   
    public void shout(String word){   
        System.out.println("string son shout:"+word);   
    } 
    public void getSalary(int m){
     System.out.println("返回的值是"+(m+bonus));
    }
    public void setBonus(int n){
     bonus=n;
    }
    private int bonus;
}public class TestOverLoad { /**
 * @param args
 */
public static void main(String[] args) {
// TODO Auto-generated method stub
        Son son=new Son(250);
        Father father=son;   
           
        son.shout("54");
        father.shout("54");
        System.out.println("下面是新的方法调用:");
        son.getSalary(300);
        father.getSalary(300);
        System.out.println("father是son类型吗?"+ (father instanceof Son));
        son.setBonus(500);
        son.getSalary(250);
        father.getSalary(250); }}
运行结果:
string son shout:54
object father shout:54
下面是新的方法调用:
返回的值是550
返回的值是550
father是son类型吗?true
返回的值是750
返回的值是750
Father能引用Son对象,用instanceof测试是Son对象,但为什么不能直接使用Son对象的方法。(比如说我在测试的时候使用father.setBonus(500),编译报错。对于一个申明为Father对象,而实际引用为子对象的对象,它与真正的子对象究竟有什么样的区别。虽然前面说Father不能引用子对象的方法,但实际上在getSalary方法上,Father引用了子对象的方法。我测试过,如果Son不覆盖Father中的getSalary方法的话(将Father中getSalary方法的参数类型设为Object时),它是不会调用子类中的方法的。我以前认为既然father被申明为Father对象,在引用son对象时,只是将son对象中对Father有用的数据给了father,father实际上还是Father类型的对象。但却不明白它为什么会调用son中的getSalary方法。【虽然我相信如果我接着看下去会弄明白这个问题的,但现在还是迫不急待的想把它贴出来和大家讨论一下。】另外也在思考动态绑定的问题,事实上是因为思想动态绑定的问题才想到这个问题上去,并自己去测试这个程序。动态绑定和静态绑定如何在这个程序中起作用,如果有人能解释的话,将非常高兴。

解决方案 »

  1.   

    Father father = new Son(250);习惯这样理解:"父类的指针指向子类的对象",father实际上是子类的对象换种说法:father编译时类型是Father,运行时类型是Son因为声明为Father,编译器只认识这个声明,而不会管这个对象实际是父类还是子类,所以只能调用父类中的方法,想调子类的方法,可以骗过编译器, 像这样,((Son)father).setBonus(500)
    小结:调用father的方法时,先回看父类中有无此方法,没有的话通不过编译,有的话,再看子类有没有重写这个方法,有就调子类的方法,没有就调父类的方法
    最后:楼主还是该好好看下 多态 的基本概念,感觉你没有理解呢..
      

  2.   

    非常感谢二楼,确实又让我弄懂了一些。暂时不结帖,希望有更多人来讨论一下。对于动态绑定的问题,还有些疑惑,先说下我自己的看法:动态绑定是编译时在父类和子父之间根据方法签名选择哪一种方法。而多态的方法选择是根据参数的不同来选择不同的方法(不限于父类子类,但不确定是否仅在一个类中的不同方法叫重载)。 
    有一种情况下是多态,而不是动态绑定,就是构造函数中的方法重载。【这么说是因为Java核心技术说如果方法是private、static、final或者是构造器时,编译器将可以准备地知道应该调用哪个方法,这种调用方式就是静态绑定。这是自己的一些不确定的理解,是否正确,希望各位证实一下。对于上例是的方法调用:        son.shout("54"); 
            father.shout("54"); 
            System.out.println("下面是新的方法调用:"); 
            son.getSalary(300); 
            father.getSalary(300); 
            System.out.println("father是son类型吗?"+ (father instanceof Son)); 
            son.setBonus(500); 
            son.getSalary(250); 
            father.getSalary(250); 这些方法的调用都是动态绑定吗?
      

  3.   

    第一次发帖,竟然只有一个回复的,觉得有点有点悲哀,还是自己找答案吧。首先,多态和动态绑定的意思:
    The fact that an object variable can refer to multiple actual types is called polymorphism. Automatically selecting the appropriate method at run time is called dynamic binding. 【Core Java2】一个对象变量实际上能指向多种类型就是多态。而这个变量又能在运行时自动的选择适当的方法来调用就叫动态绑定。也就是说多态就是能一个变量能指向多种类型的对象,而它自身就具有选择适当方法的功能,这个功能就是动态绑定。(自己的理解)。因此,二楼说的也很正确,father在定义的时候就是个Father类,实际上指向的是一个son类。因此,它实际上就既是一个son类,也是一个father类(但归根到底,它是一个Son类)。如果Son类中的方法将它覆盖了,它就只能调用子类中的方法(因为前面的方法对它是不适用的)。这也是在类设计过程中的“is a”规则,也可以说是置换法则(substitution principle)。引用Core Java2:
    A simple rule enables you to know whether or not inheritance is the right design for your data. The "is-a" rule states that every object of the subclass is an object of the superclass. Another way of formulating the "is-a" rule is the substitution principle. That principle states that you can use a subclass object whenever the program expects a superclass object.动态绑定中的“根据方法签名正确选择适当的方法”,选择实际上也是指在父类和子类中去选择正确的方法。我之所以搞混了,主要原因是因为在书中的那一节的标题是动态绑定(Dynamic Binding),但接下来介绍的却是调用对象方法的执行过程。仅在其中的第3点中介绍的是动态绑定。因此这里要补充一下,动态绑定是否是根据方法签名来调用的,还有待商榷(看各人自己的理解)。下面引用第三点:3.If the method is private, static, final, or a constructor, then the compiler knows exactly which method to call. (The final modifier is explained in the next section.) This is called static binding. Otherwise, the method to be called depends on the actual type of the implicit parameter, and dynamic binding must be used at run time. In our example, the compiler would generate an instruction to call f(String) with dynamic binding.【Core Java2】这里也就是说,对动态绑定起决定作用的,其实是隐式参数(implicit parameter)。下面我自己对隐式参数作一下解释,隐式参数是在方法调用中没有在参数列表中写出来的参数。如,在调用方法e.getSalary(arg1,arg2)时,实际上在定义中应该是this.getSalary(arg1,arg2),this=e 这个this参数,也就是e的实际类型就是隐式参数。(按前面的说的,似乎隐式参数并不在方法签名的范围内)。而要看e的实际引用类型来判断选择哪一个方法就是动态绑定了。小结:回头看来,确实是我对多态一知半解,理解不深。当然,也可能是以前错误理解的“多态是由方法的重载来实现的”这一思想误导了自己。另外看书不够仔细也是一个原因(如前面提到的,对动态绑定的理解,误以为前面有个动态绑定的标题,后面讲的全都是动态绑定实现的过程。)当然,上面虽然引用了很多Java核心技术中的原话,但主要也只是自己的理解,可能还有理解不全面,甚至错误的地方,希望后面仍然有人讨论。