1. 程式人生 > >Java課堂疑問解答與思考5

Java課堂疑問解答與思考5

grand 為什麽 alt obj urn com 自己 text 語句

一:運行 TestInherits.java 示例,觀察輸出,總結。

TestInherits.java

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("Hello.Grandparent.");

   System.out.println("Parent Created");
  // super("Hello.Grandparent.");

  }

}

class Child extends Parent
{

public Child()
  {
   System.out.println("Child Created");

  }

}

public class TestInherits


{

  public static void main(String args[])
  {

    Child c = new Child();
  }

}

總結:

通過 super 調用基類構造方法,必須是子類構造方法中的第一個語句。否則會報錯。運行結果如下:

技術分享技術分享

為什麽子類的構造方法在運行之前,必須調用父類的構造方法?能不能反過來?為什麽不能反過來?

答:

構造一個對象,先調用其構造方法,來初始化其成員函數和成員變量。
子類擁有父類所有的變量及方法,父類沒有子類的部分變量和方法。
如果不調用,則從父類繼承而來的成員變量和成員方法得不到正確的初始化。
不能反過來調用也是這個原因,因為父類根本不知道子類有神魔變量而且這樣一來子類也得不到初始化的父類變量,導致程序運行出錯!

二、直接輸出一個不可變的類的對象,會有什麽結果?

程序源碼示例:

class A{}

public class ExplorationJDKSource {

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

}

運行結果:類型名+@+隨機數

技術分享

原因:

main方法實際上調用的是祖類函數: public void println(Object x),這一方法內部調用了String類的valueOf方法。

valueOf方法內部又調用Object.toString方法:

技術分享

hashCode()方法是本地方法,由JVM設計者實現: public native int hashCode();

所以通過層層調用結果就顯示出了 類名+@+哈希值。

三、我們來看Fruit.java 代碼,總結原因。

Fruit.java

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

運行結果

技術分享

總結:

Fruit類覆蓋了Object類的toString方法。

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

四、

現在有三個類:

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;

答:程序運行結果

技術分享

第二行與第四行出錯。

將父類賦值給子類時需要強制轉化,子類賦值給父類時不用強制轉化。父類的兩個子類相互賦值時也必須強制轉化。

五、請看下面的“變態”類。程序運行結果是什麽?你如何解釋會得到這樣的輸出? 計算機是不會出錯的,之所以得 到這樣的運行結果也是有原因的, 那麽從這些運行結果中,你能總 結出Java的哪些語法特性?

程序源碼:

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);
  }
}
public class Fruit
{
  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();

  }
}

運行結果:

技術分享

總結:

當子類與父類擁有一樣的方法,並且讓一個父類變量引用一個子類對象時,到底調用哪個方法,由對象自己的“真實”類型所決定,這就是說:對象是子類型的,它就調用子類型的方法,是父類型的,它就調用父類型的方法。 這個特性實際上就是面向對象“多態”特性的具體表現。

如果子類與父類有相同的字段,則子類中的字段會代替或隱藏父類的字段,子類方法中訪問的是子類中的字段(而不是父類中的字段)。如果子類方法確實想訪問父類中被隱藏的同名字段,可以用super關鍵字來訪問它。 如果子類被當作父類使用,則通過子類訪問的字段是父類的!

Java課堂疑問解答與思考5