今天做题时,很好地认识了Java特性中的多态,结合构造方法,认识到了向上转型中会出现的状况:
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
(摘自http://blog.csdn.net/chenssy/article/details/12786385)
而由于多态,在运行时可能会出现向上转型的情况,下面请看例子:
定义Father类:
<span style="font-size:18px;">public class Father {
int i = 4;
Father (){
Cal(14);
}
void Cal(int v){
i= v+i;
}
void toPrint(){
System.out.println("FatherCal:"+i);
}
}</span>
<span style="font-size:18px;">定义一个Son类,并继承Father类,重写Father类中的Cal;</span>
<span style="font-size:18px;">public class Son extends Father{
Son(){
Cal(6);
}
void Cal(<span style="font-family: Arial, Helvetica, sans-serif;">int v){</span></span>
<span style="font-size:18px;"> i += v*3;
System.out.println("SonCal:"+i);
}
}</span>
测试类:
<span style="font-size:18px;">public class test {
public static void main(String[] args) {
runTest(new Son());
//System.out.println("/*********/");
// Father fa = new Son();
// runTest(fa);
}</span>
<span style="font-size:18px;">
public static void runTest(Father m){
m.Cal(8);
m.toPrint();
Son s = (Son) m;
s.Cal(9);
m.toPrint();
}
}</span>
结果:
SonCal:46
SonCal:64
SonCal:88
m.toPrint().FatherCal:88
SonCal:115
m.toPrint().FatherCal:115
结果解析:第一个次输出 SonCal 是调用Father构造器中的Cal(14),由于Son重写了Cal( ),所以调用的是Son中的Cal(14),即 i= 4+14*3 = 46;第二次输出SonCal是调用Son的构造器,此时 i = 46 + 3*6=64,此时Son实例化结束;接着执行 m.Cal(8),虽然此时Son已经被向上转型为Father,但是由于Son中重写(注意不是重载,重载结果不一样)Cal(8),所以调用的是Son中的Cal(8),所以 i=64 + 3*8 = 88,并输出;接着对m进行强转,但Java的使用引用,此时s还是指向m,但是m的功能加强了,具有了Son的方法,所以 i=88 + 3*9 = 115;
实际上是这样的,将main做一下修改:
<span style="font-size:18px;">public static void main(String[] args) {
runTest(new Son());
System.out.println("/*********/");
Father fa = new Son();
runTest(fa);
}</span>
结果一样:
SonCal:46
SonCal:64
SonCal:88
m.toPrint().FatherCal:88
SonCal:115
m.toPrint().FatherCal:115
/*********/
SonCal:46
SonCal:64
SonCal:88
m.toPrint().FatherCal:88
SonCal:115
m.toPrint().FatherCal:115
但假如Son是重载Father的Cal方法,改变下参数类型就是进行了重载 即:
<span style="font-size:18px;">public class Son extends Father{
Son(){
Cal(6);
}
void Cal(double v){
i += v*3;
System.out.println("SonCal:"+i);
}
}</span>
结果为:
m.toPrint().FatherCal:32
m.toPrint().FatherCal:41
首先是调用Father的构造函数,此时i= 4 + 14 = 18,然后调用Son的构造函数,执行Cal(6),但是由于向上转型会丢失重载自父类的方法,即无法调用子类中重载自父类的方法,所以执行的是 i= 18+6 = 24;接着调用m.Cal(8),即执行Father 中的Cal(),所以i=24+8 =32;强转后调用Cal(9),同样调用Father中的Cal(),所以 i=32+9=41。
详细的多态及强转可以参考以下链接:
强制转换: http://blog.csdn.net/chenssy/article/details/14111307
多态,向上转型 :http://blog.csdn.net/chenssy/article/details/12786385