課程作業06-匯總整理
06-繼承與多態
實驗性問題總結
一、為什麽子類的構造方法在運行之前,必須調用父類的構造方法?能不能反過來?為什麽不能反過來? 子類是從父類繼承來的,所以想用子類創建對象的時候,必須要先建立父類的對象,子類有父類的屬性和方法;就要給父類的屬性分配內存空間,在創建對象的時候如果父類中的數據需要初始化,那麽就必須要調用。不能反過來,如果反過來,就相當於不知道父類要繼承幾個子類。
二、參看ExplorationJDKSource.java示例,此示例中定義了一個類A,它沒有任何成員:class A { }示例直接輸出這個類所創建的對象 public static void main(String[] args) { System.out.println(new A());}結果截圖:
結果分析:
此程序內部調用了String類的valueOf()方法而valueOf方法內部又調用Object.toString方法:public String toString(){return getClass().getName()+”@”+Integer.toHexString(hashCode());}
hashCode方法是本地方法,由JVM設計者實現:public native int hashCode().
三、看一段代碼,分析運行結果:
代碼:
public class Fruit
{
public String toString()
{
return "Fruit toString.";
}
public static void main(String args[])
{
Fruit f=new Fruit();
System.out.println("f="+f);
System.out.println("f="+f.toString());
}
}
運行結果:
分析:
在“+”運算中,當任何一個對象與一個String對象,連接時,會隱式地調用其toString()方法,默認情況下,此方法返回“類名 @ + hashCode”。為了返回有意義的信息,子類可以重寫toString()方法。
四、請自行編寫代碼測試以下特性(動手動腦):在子類中,若要調用父類中被覆蓋的方法,可以使用
class Grandparent{
public Grandparent()
{
System.out.println("Grandparent Created.");
}
public Grandparent(String string)
{
System.out.println("Grandparent Created.String:"+string);
}
}
class Parent extends Grandparent{
public Parent()
{
super("20163548");
System.out.println("Parent Created");
}
}
class Child extends Parent{
public Child()
{
System.out.println("Child Creatd");
}
}
public class AAA{
public static void main(String[] args)
{
Child c=new Child();
}
}
運行結果截圖:
五、現在有三個類:class Mammal{}class Dog extends Mammal {}class Cat extends Mammal{}針對每個類定義三個變量並進行初始化 Mammal m=null ; Dog d=new Dog(); Cat c=new Cat();下列語句哪一個將引起編譯錯誤?為什麽?哪一個會引起運行時錯誤?為什麽? m=d; d=m; d=(Dog)m; d=c; c=(Cat)m;先進行自我判斷,得出結論後,運行TestCast.java實例代碼,看看你的判斷是否正確。源程序代碼:
class Mammal{}
class Dog extends Mammal {}
class Cat extends Mammal{}
public class TestCast
{
public static void main(String args[])
{
Mammal m;
Dog d=new Dog();
Cat c=new Cat();
m=d;
//d=m;
d=(Dog)m;
//d=c;
c=(Cat)m;
}
}
運行錯誤分析:
d=m顯示錯誤:類型不匹配:不能從mammal轉換為dog
d=c顯示錯誤:類型不匹配:不能從cat轉換為dog
六、運行以下測試代碼,回答問題
public class ParentChildTest {
public static void main(String[] args) {
Parent parent=new Parent();
parent.printValue();
Child child=new Child();
child.printValue();
parent=child;
parent.printValue();
parent.myValue++;
parent.printValue();
((Child)parent).myValue++;
parent.printValue();
}
}
class Parent{
public int myValue=100;
public void printValue()
{
System.out.println("Parent.printValue(),myValue="+myValue);
}
}
class Child extends Parent{
public int myValue=200;
public void printValue()
{
System.out.println("Child.printValue(),myValue="+myValue);
}
}
1.左邊的程序運行結果是什麽?
2.你如何解釋會得到這樣的輸出?
a.創建父類對象parent,parent調用父類printValue方法,輸出100。
b.創建子類對象child,child調用子類printValue方法,輸出200。
c.把子類對象賦值給父類對象,賦值後的parent.printValue();相當於child.printValue();所以輸出200。
d.被賦值後的父類對象對數據成員的操作依然是對父類的數據成員進行操作,並沒有對子類數據成員進行操作,只是將父類的myValue值+1,而子類的myValue值並沒有改變,所以 parent.printValue();輸出200。
e.使用了強制類型轉換,結果是對子類的myValue+1,而parent已經被子類對象賦值,所以輸出201。
3.計算機是不會出錯的,之所以得到這樣的運行結果也是有原因的,那麽從這些運行結果中,你能總結出Java的哪些語法特性?
當子類與父類擁有一樣的方法,並且讓一個父類變量引用一個子類對象時,到底調用哪個方法,由對象自己的“真實”類型所決定,這就是說:對象是子類型的,它就調用子類型的方法,是父類型的,它就調用父類型的方法。
如果子類與父類有相同的字段,則子類中的字段會代替或隱藏父類的字段,子類方法中訪問的是子類中的字段(而不是父類中的字段)。如果子類方法確實想訪問父類中被隱藏的同名字段,可以用super關鍵字來訪問它。
如果子類被當作父類使用,則通過子類訪問的字段是父類的!
七、請使用javap查看編譯器為TestPolymorphism.java生成的字節碼指令,然後通過互聯網搜索資料,嘗試從底層開始理解Java編譯器是如何為多態代碼生成字節碼指令,在程序運行過程中,多態特性又是如何實現的。
class Parent
{
public int value=100;
public void Introduce()
{
System.out.println("I‘m father.");
}
}
class Son extends Parent
{
public int value=101;
public void Introduce()
{
System.out.println("I‘m son.");
}
}
class Daughter extends Parent
{
public int value=102;
public void Introduce()
{
System.out.println("I‘m daughter.");
}
}
public class A {
public static void main(String[] args)
{
Parent p=new Parent();
p.Introduce();
System.out.println(p.value);
p=new Son();
p.Introduce();
System.out.println(p.value);
p=new Daughter();
p.Introduce();
System.out.println(p.value);
}
}
多態依賴於類型和實現的分離,多用來把接口和實現分離。
課程作業06-匯總整理