public class ploytest {
public static void main(String[] args) {
A a = new A();
B b = new B();
a.s = "[AA]";
b.s = "[BB]";
a = b;
System.out.println(a.s);
System.out.println(b.s);
System.out.println(a.getS());
System.out.println(b.getS());
System.out.println("====================");
((A)b).s = "[AA]";
System.out.println(a.s);
System.out.println(b.s);
System.out.println(a.getS());
System.out.println(b.getS());
}
}
class A {
String s = "[A]";
String getS() {
return s;
}
}
class B extends A{
String s = "";
String getS() {
return s;
}
}
The results:
[A]
[BB]
[BB]
[BB]
====================
[AA]
[BB]
[BB]
[BB]
其實結果不重要。一運行就知道。主要是原理。
將子類對象賦值給父類對象,所得到對象是這樣的一個對象:
它是一個編譯是為父類對象,但運行卻是一個子類對象,具體特征如下.
1.被聲明為父類對象
2.擁有父類屬性
3.占用子類的內存空間
4.子類方法覆蓋父類的方法時,此時對象調用的是子類的方法;否則,自動調用繼承父類的方法.
5.我人認為這個對象既不是父類對象,也不是子類對象.當我們用到它的方法時,
我便把它看成子類對象;若用到它的屬性時,我把它看成父類對象.
它是一個占用父類屬性,而使用子類方法的對象.至于到底是什么對象,我認為還是得根據聲明來,它應算是父類對象,但擁有子類方法.
這就是為什么第一個a.s為[A]的道理了。
(A)b是向上轉型。(A)b.s相當于把"[AA]"賦值給b的父類對象。所以由上面可以看出。a.s為[AA]而其他的都同上
System.out.println(a.getS()); System.out.println(b.getS()); 再看這條語句: a.s = "[AA]"; //這是給對象a中s賦值,跟上轉型.s一點關系都沒有,不要被弄混,緊記這里面有3個對象,你就會明白的
看了前幾個留言怎么也沒看出來為什么"第一個a.s為[A]的道理". 依我看,這題有三個對象,希望提問者不要弄混. 這三個對象分別是a,b,b的上轉型對象, a = b; //自這條語句以下,a便不是a對象,而是b的上轉型對象 System.out.println(a.s); System.out.println(b.s);
關鍵還是a = b; 這句話,其相當于a =(A) b; 所以第一句打印的是[A] 而非[AA]
java中有虛函數,但是沒指針,那也許會有這樣的問題,那java是怎么實現多態(tài)的?
java中可以肯定是有虛函數的,而且我們如果不申明為final形他默認就是虛函數.不用vitual申明.
"In Java, you do not need to declare a method as virtual. Dynamic binding is the default behavior. If you do not want a method to be virtual, you tag it as final"--from <core java2 :volum I>.
java中沒顯示的和c++中的指針,但是他有地址的概念的.而且所有我們申明的"對象"其實就是地址(或叫句柄),給他賦值就是把他指向一個內存單元.當然也可以改變他的指向.其實我們"對象"的賦值操作全是地址在變東,對象還是沒有變的.那也許有人會說那樣的話不是會產生很多沒有"對象" (句柄)的內存區(qū)域.是的是會產生,但是java的垃圾收集機制會給我們回收這樣的內存"泄漏".所以我們只關心我們操作的對象就行,其他的我們不用的對象的后事垃圾收集會給我們干.
明白了在java中的"對象"而非我們c++中理解的對象.而實際上是指針(句柄)那多態(tài)當然可以實現.
下面舉個"對象"賦值(引用)的例子說明,全是地址在變,而非真的內存單元.