1. 程式人生 > >動手動腦(課堂作業05)

動手動腦(課堂作業05)

一個 顯示 truct 重載 cto cast {} 進行 string

1,思考

技術分享

class Grandparent 
{


    public Grandparent()
     {

            System.out.println("GrandParent Created.");
    
}


    public Grandparent(String string) 
    {

            System.out.println("GrandParent Created.String:" + string);
    
 }

}



class Parent2 extends Grandparent
{


    
public Parent2() { //super("Hello.Grandparent."); System.out.println("Parent Created"); // super("Hello.Grandparent."); } public Parent2(String a) { System.out.println("PPP"+a); } } class Child2 extends Parent2 { public
Child2() { //super("GGG"); System.out.println("Child Created"); } } public class TestInherits { public static void main(String args[]) { Child2 c = new Child2(); } }

運行結果為:

技術分享

顯然運行子類的構造函數會先執行父類的構造函數。若將//super("Hello.Grandparent.");前//去掉之後運行就結果就會變成:

技術分享

有了super()語句會執行其調用的構造函數,若將其放在第二行,則會報錯

技術分享

(構造函數調用必須是構造函數中的第一個語句)這是顯示的錯誤。

總結:通過 super 調用父類構造方法,必須是子類構造方法中的第一個語句。若父類中同時存在有參構造函數和無參構造函數,若子類構造函數什麽也沒寫則默認調用無參構造函數,若加上super(),則根據super()來確定,若父類只有有參構造函數,則必須在寫子類構造函數時加上super();

2,思考

技術分享

構造函數(constructor)是一種特殊的方法 。主要用來在創建對象時初始化對象, 即為對象成員變量賦初始值,總與new運算符一起使用在創建對象的語句中 。特別的一個類可以有多個構造函數 ,可根據其參數個數的不同或參數類型的不同來區分它們 即構造函數的重載。構造函數的功能主要用於在類的對象創建時定義初始化的狀態。構造一個對象,先調用其構造方法,來初始化其成員函數和成員變量。子類擁有父的成員變量和成員方法,如果不調用,則從父類繼承而來的成員變量和成員方法得不到正確的初始化。不能反過來調用也是這個原因,因為父類根本不知道子類有神魔變量而且這樣一來子類也得不到初始化的父類變量,導致程序運行出錯!

3,解密

技術分享

public class ExplorationJDKSource {

    /**
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(new A());
    }

}

class A{}

通過javap反編譯得:

技術分享

可以看到println()那條語句到底調用了Ljava/lang/Object使用Eclipse打開JDK源碼,查看真正被執行的代碼是

技術分享

4,探索:觀看以下代碼,,註意最後一句,一個字串和一個對象“相加”

技術分享

得到的結果為:

技術分享

分析:示例中,Fruit類覆蓋了Object類的toString方法。在“+”運算中,當任何一個對象與一個String對象,連接時,會隱式地調用其toString()方法,默認情況下,此方法返回“類名 @ + hashCode”。為了返回有意義的信息,子類可以重寫toString()方法。若不重寫結果為:

技術分享

5,請自行編寫代碼測試以下特性(動手動腦): 在子類中,若要調用父類中被覆蓋的方法,可以使用super關鍵字。

代碼如下:

class ddd
{
    int num;
    ddd()
    {
        this.num=1;
    }
    void shuchu()
    {
        System.out.println("父類"+num);
    }
}
class aaa extends ddd
{
    aaa()
    {
        this.num=2;
    }
    void shuchu()
    {
        super.shuchu();
        System.out.println("子類"+num);
    }
}
public class demo {
    public static void main(String[]args)
    {
        aaa wa=new aaa();
        wa.shuchu();
    }

}

運行結果為:

技術分享

若將super.shuchu()註釋掉,結果為:

技術分享

6,怎樣判斷對象是否可以轉換?

可以使用instanceof運算符判斷一個對象是否可以轉換為指定的類型: Object obj="Hello"; if(obj instanceof String) System.out.println("obj對象可以被轉換為字符串");

public class TestInstanceof
{
    public static void main(String[] args) 
    {
        //聲明hello時使用Object類,則hello的編譯類型是Object,Object是所有類的父類
        //但hello變量的實際類型是String
        Object hello = "Hello";
        //String是Object類的子類,所以返回true。
        System.out.println("字符串是否是Object類的實例:" + (hello instanceof Object));
        //返回true。
        System.out.println("字符串是否是String類的實例:" + (hello instanceof String));
        //返回false。
        System.out.println("字符串是否是Math類的實例:" + (hello instanceof Math));
        //String實現了Comparable接口,所以返回true。
        System.out.println("字符串是否是Comparable接口的實例:" + (hello instanceof Comparable));
        String a = "Hello";
        //String類既不是Math類,也不是Math類的父類,所以下面代碼編譯無法通過
        //System.out.println("字符串是否是Math類的實例:" + (a instanceof Math));
    }
}

結果為:

技術分享

7,小測試:

現在有三個類: 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;

我認為第一句不出錯,可以用子類給父類賦值,因為子類裏有父類裏所有的變量;第二句會出錯,不能用父類變量來給子類賦值,父類裏面不一定包含不全子類裏所有的變量;第三句不會出錯若要用子類給父類賦值必須強轉;第四句出錯,這兩個變量間沒有直接關系;第五句對同第三句。

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;

    }
}

結果:

技術分享

第二句錯誤顯示為:類型不匹配:不能從 Mammal 轉換為 Dog

第三句錯誤顯示為:類型不匹配:不能從 Cat 轉換為 Dog

8,動動手:

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);
    }
}

結果:

技術分享

解釋:

先定義了一個父類對象以及子類變量,輸出就顯示出來第一二句,然後用children對象給parent對象賦值,parent對象的myValue變為200;parent函數printvalue也被覆蓋,於是就有了第三句,value++是先輸出再加一,於是輸出第四句,然後強轉輸出,這是value已經是201,先輸出在加一有了第五句。

思考:但我又加了一行代碼如下:

技術分享

運行結果如下:

技術分享

發現父類對象的數據值加了1

之後再改如下:

技術分享

結果為:

技術分享

我在網上查了查發現過程為:

第一個100:是parent調用PrintValue方法輸出parent類中myValue值為100;

第二個200:是child調用PrintValue方法輸出child類中myValue值為200;

第三個200:是parent = child,將子類對象的賦值給父類,但此時parent只能調用子類的方法,調用子類PrintValue時,輸出的當然是子類的myValue值200。

第四個200:雖然parent = child,但parent不能調用子類的變量,所以parent.myValue++;只是將父類對象中的變量myValue值+1但不能改變子類的myValue值,但調用的是子類PrintValue方法時,輸出的是子類的myValue值200。

第五個201:(Child)parent,強制轉化parent為child對象,此時parent完全成為child對象,所以輸出值為201。

原因:

(1):當子類和父類擁有同名方法時,並且讓一個父類變量引用一個子類對象時,調用哪個方法由自己的真實類型來決定。

(2):如果子類與父類有相同的字段,則子類中的字段會代替或隱藏父類的字段,子類方法中訪問的是子類中的字段(而不是父類中的字段)。

動手動腦(課堂作業05)