JavaRush /Java Blog /Random-TW /引用類型的擴展和收縮

引用類型的擴展和收縮

在 Random-TW 群組發布
你好!在之前的一講中,我們討論了原始型別的轉換。讓我們簡單回憶一下我們正在談論的內容。 引用類型的擴展和收縮 - 1我們根據原始類型(在本例中為數字)佔用的記憶體量將它們表示為嵌套娃娃。您還記得,無論是在現實生活中還是在 Java 程式設計中,將較小的嵌套娃娃放入較大的嵌套娃娃中都是很簡單的。
public class Main {
   public static void main(String[] args) {
        short smallNumber = 100;
        int bigNumber =  smallNumber;
        System.out.println(bigNumber);
   }
}
這是自動轉換或擴展 的範例。它會自行發生,因此無需編寫額外的程式碼。最後,我們並沒有做任何不尋常的事情:我們只是將一個較小的嵌套娃娃放入較大的嵌套娃娃中。如果我們反其道而行之,將一個大的俄羅斯娃娃放入一個較小的俄羅斯娃娃中,那就是另一回事了。這在人生中是做不到的,但是在程式設計上卻可以做到。但有一點要注意。如果我們嘗試將一個值int放入變數中short,則不會那麼容易。畢竟,變數只能容納 16 位元訊息short,但值卻int需要 32 位元!結果,傳輸的值將會失真。編譯器會給我們一個錯誤(「夥計,你正在做一些可疑的事情!」),但是如果我們明確指定我們將值轉換為什麼類型,它仍然會執行這樣的操作。
public class Main {

   public static void main(String[] args) {

       int bigNumber = 10000000;

       bigNumber = (short) bigNumber;

       System.out.println(bigNumber);

   }

}
在上面的例子中,我們就是這樣做的。操作已完成,但由於short32 位元中只有 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類別Pet或類別方法會起作用嗎Animal?在繼續閱讀之前嘗試證明你的答案是正確的。這就是結果! 我是 Pet 為什麼答案是這樣的?這很簡單。我們有一個父變數和一個子物件。透過寫:
Animal animal = new Pet();
我們擴展了引用類型Pet並將其物件儲存在變數中Animal。與原始類型一樣,Java 中引用類型的擴充功能是自動完成的。無需為此編寫額外的程式碼。現在我們有一個子物件附加到父引用,結果我們看到該方法在子類別上被呼叫。如果您仍然不完全理解這段程式碼的工作原理,請用簡單的語言重寫它:
Животное животное = new ДомашнееЖивотное();
這沒有問題,對吧?想像一下這是現實生活,本例中的連結是一個簡單的紙質標籤,上面寫著「動物」。如果你把這樣一張紙貼在任何寵物的項圈上,一切都會好起來的。任何寵物仍然是動物!相反的過程,即沿著繼承樹向下移動到繼承人,是一個縮小範圍:
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!
   }
}
編譯器會拋出錯誤!是什麼原因? 事實上,您正在嘗試將父物件指派給子變數。 換句話說,你想要這樣做:
ДомашнееЖивотное домашнееЖивотное = new Животное();
但如果我們明確指出我們試圖轉換的類型,我們就會成功嗎?數字看起來很有效,讓我們試試看!:)
public class Main {

   public static void main(String[] args) {

       Pet pet = (Pet) new Animal();
   }
}
線程“main”中出現異常 java.lang.ClassCastException:動物無法轉換為 Pet 錯誤!這次編譯器沒有抱怨,但結果我們收到了一個異常。我們已經知道原因:我們正在嘗試將父物件指派給子變數。事實上,為什麼不能這樣做呢? 因為並非所有動物都是寵物。 您創建了一個物件Animal並嘗試將其指派給一個變數Pet。但是,例如,土狼也是家畜Animal,但它不是。Pet換句話說,當你寫:
Pet pet = (Pet) new Animal();
new Animal()任何動物都可以 在那裡,而且不一定是家養的!當然,你的變數Pet pet只適合存放寵物(及其後代),而不適合所有人。因此,對於這種情況,Java 中創建了一個特殊的異常——ClassCastException轉換類別時出錯。讓我們再說一遍,以便更清楚。父變數(引用)可以指向後代類別的物件:
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 pet =  new Pet();
在前面的範例中,它是一個物件Animal
Pet pet = (Pet) new Animal();
後代變數不能分配給祖先物件。相反,你可以做到。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION