CodeGym /Java Blog /Toto sisi /引用類型的擴大和縮小
John Squirrels
等級 41
San Francisco

引用類型的擴大和縮小

在 Toto sisi 群組發布
你好!在過去的課程中,我們討論了轉換原始類型。讓我們簡要回顧一下討論的內容。 引用類型的擴大和縮小 - 1我們將基本類型(在本例中為數字類型)想像成嵌套的玩偶,它們的大小根據它們佔用的內存量而變化。您會記得,在現實生活和 Java 編程中,將較小的玩偶放入較大的玩偶中都很簡單。

public class Main {
   public static void main(String[] args) {
       int bigNumber = 10000000;
       short smallNumber = (short) bigNumber;
       System.out.println(smallNumber);
   }
}
這是一個自動轉換或加寬 的例子。它會自動發生,因此您無需編寫額外的代碼。最後,我們並沒有做任何不尋常的事情:我們只是將一個較小的娃娃放入一個較大的娃娃中。如果我們試圖反其道而行之,將較大的俄羅斯套娃放入較小的套娃中,那就另當別論了。你不能在現實生活中做到這一點,但在編程中你可以。但有一個細微差別。如果我們嘗試將 an 放入變量intshort,事情就不會那麼順利了。畢竟short變量只保存了16位的信息,而an卻int佔據了32位!結果,傳遞的值被扭曲。編譯器會給我們一個錯誤('伙計,你在做一些可疑的事情!'). 但是,如果我們明確指出要將我們的值轉換為的類型,它將繼續執行操作。

public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
這就是我們在上面的例子中所做的。該操作已執行,但由於該short變量只能容納 32 個字節中的 16 個,因此最終值被扭曲,我們得到數字-27008。這種操作稱為顯式轉換或縮小

擴大和縮小引用類型的例子

現在讓我們來談談同樣的運算符,但不是應用於基本類型,而是應用於對象和引用變量!這在 Java 中如何工作?其實很簡單。有些對像是不相關的。假設它們不能相互轉換是合乎邏輯的,既不能顯式地也不能自動地:

public class Cat {
}

public class Dog {
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Dog(); // Error!

   }

}
在這裡,當然,我們得到一個錯誤。和類彼此不相關,我們還沒有編寫一個“轉換器”來從一個轉移到另一個CatDog我們不能這樣做是有道理的:編譯器不知道如何將這些對像從一種類型轉換為另一種類型。如果對像是相關的,那又是另一回事了!相關如何?最重要的是,通過繼承。讓我們嘗試使用繼承來創建一個小的類系統。我們將有一個通用類來表示動物:

public class Animal {

   public void introduce() {

       System.out.println("I'm Animal");
   }
}
每個人都知道動物可以被馴化(寵物)或野生:

public class WildAnimal extends Animal {

   public void introduce() {

       System.out.println("I'm WildAnimal");
   }
}

public class Pet extends Animal {

   public void introduce() {

       System.out.println("I'm Pet");
   }
}
例如,以犬科動物為例——我們有家犬和土狼:

public class Dog extends Pet {

   public void introduce() {

       System.out.println("I'm Dog");
   }
}



public class Coyote extends WildAnimal {

   public void introduce() {

       System.out.println ("I'm Coyote");
   }
}
我們特地選擇了最基本的類,使它們更容易理解。我們真的不需要任何字段,一個方法就足夠了。讓我們嘗試執行這段代碼:

public class Main {

   public static void main(String[] args) {

       Animal animal = new Pet();
       animal.introduce();
   }
}
您認為控制台上會顯示什麼?會調用類的方法還是類introduce的方法?在繼續閱讀之前嘗試證明你的答案是正確的。這就是結果! 我是寵物 為什麼我們得到那個?一切都很簡單。我們有一個父變量和一個後代對象。通過寫作, PetAnimal

Animal animal = new Pet();
我們擴大了一個Pet引用並將其分配給一個Animal變量。與原始類型一樣,引用類型在 Java 中會自動擴展。您不需要編寫額外的代碼來實現它。現在我們有一個分配給父引用的後代對象。結果,我們看到方法調用是在子類上進行的。如果您仍然不完全理解此代碼為何有效,請用通俗易懂的語言重寫它:

Animal animal = new DomesticatedAnimal();
這個沒有問題吧?想像一下這是真實的生活,參考只是一張寫有“動物”的紙質標籤。如果你把那張紙貼在任何寵物的項圈上,一切都會正確。畢竟,任何寵物都是動物!相反的過程——將繼承樹向下移動到後代——正在縮小:

public class Main {

   public static void main(String[] args) {

       WildAnimal wildAnimal = new Coyote();

       Coyote coyote = (Coyote) wildAnimal;

       coyote.introduce();
   }
}
如您所見,這裡我們清楚地指出了我們要將對象轉換為的類。我們以前有一個WildAnimal變量,現在我們有一個Coyote,它在繼承樹上處於較低位置。如果沒有明確指示,編譯器將不允許這樣的操作,這是有道理的,但如果我們在括號中指示類型,那麼一切正常。 參考類型的擴大和縮小 - 2考慮另一個更有趣的例子:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Animal(); // Error!
   }
}
編譯器產生錯誤!但為什麼? 因為您正試圖將父對象分配給後代引用。 換句話說,你正在嘗試做這樣的事情:

DomesticatedAnimal domesticatedAnimal = new Animal();
好吧,如果我們明確指定我們試圖轉換成的類型,也許一切都會起作用? 這對數字有效——讓我們試一試吧!:)

public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
線程“main”中的異常 java.lang.ClassCastException: Animal cannot be cast to Pet 錯誤!編譯器這次沒有對我們大喊大叫,但我們以異常結束。我們已經知道原因:我們試圖將父對象分配給後代引用。但是為什麼你不能那樣做呢? 因為不是所有的動物都是家養動物。 您創建了一個Animal對象並試圖將其分配給一個Pet變量。土狼也是一個Animal,但它不是Pet。換句話說,當你寫

Pet pet = (Pet) new Animal();
new Animal()可以代表任何動物,不一定是寵物!當然,您的Pet pet變量僅適用於存儲寵物(及其後代),而不適用於任何類型的動物。ClassCastException這就是為什麼為在轉換類時發生錯誤的情況創建特殊的 Java 異常的原因。讓我們再次回顧它以使事情更清楚。父引用可以指向子類的實例:

public class Main {

   public static void main(String[] args) {

       Pet pet = new Pet();
       Animal animal = pet;

       Pet pet2 = (Pet) animal;
       pet2.introduce();
   }
}
例如,在這裡我們沒有問題。我們有一個Pet由變量引用的對象Pet。後來,一個Animal引用指向了同一個對象。之後,我們轉換animalPet. 順便說一句,為什麼這對我們有用?上次我們有一個例外!因為這次我們原來的對像是一個Pet

Pet pet = new Pet();
但在最後一個例子中,它是一個Animal對象:

Pet pet = (Pet) new Animal();
您不能將祖先對象分配給後代變量。你可以做相反的事情。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION