<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## [類型轉換檢測](https://lingcoder.gitee.io/onjava8/#/book/19-Type-Information?id=%e7%b1%bb%e5%9e%8b%e8%bd%ac%e6%8d%a2%e6%a3%80%e6%b5%8b) 直到現在,我們已知的 RTTI 類型包括: 1. 傳統的類型轉換,如 “`(Shape)`”,由 RTTI 確保轉換的正確性,如果執行了一個錯誤的類型轉換,就會拋出一個`ClassCastException`異常。 2. 代表對象類型的`Class`對象. 通過查詢`Class`對象可以獲取運行時所需的信息. 在 C++ 中,經典的類型轉換 “`(Shape)`” 并不使用 RTTI。它只是簡單地告訴編譯器將這個對象作為新的類型對待. 而 Java 會進行類型檢查,這種類型轉換一般被稱作“類型安全的向下轉型”。之所以稱作“向下轉型”,是因為傳統上類繼承圖是這么畫的。將`Circle`轉換為`Shape`是一次向上轉型, 將`Shape`轉換為`Circle`是一次向下轉型。但是, 因為我們知道`Circle`肯定是一個`Shape`,所以編譯器允許我們自由地做向上轉型的賦值操作,且不需要任何顯式的轉型操作。當你給編譯器一個`Shape`的時候,編譯器并不知道它到底是什么類型的`Shape`——它可能是`Shape`,也可能是`Shape`的子類型,例如`Circle`、`Square`、`Triangle`或某種其他的類型。在編譯期,編譯器只能知道它是`Shape`。因此,你需要使用顯式地進行類型轉換,以告知編譯器你想轉換的特定類型,否則編譯器就不允許你執行向下轉型賦值。 (編譯器將會檢查向下轉型是否合理,因此它不允許向下轉型到實際不是待轉型類型的子類類型上)。 RTTI 在 Java 中還有第三種形式,那就是關鍵字`instanceof`。它返回一個布爾值,告訴我們對象是不是某個特定類型的實例,可以用提問的方式使用它,就像這個樣子: ~~~ if(x instanceof Dog) ((Dog)x).bark(); ~~~ 在將`x`的類型轉換為`Dog`之前,`if`語句會先檢查`x`是否是`Dog`類型的對象。進行向下轉型前,如果沒有其他信息可以告訴你這個對象是什么類型,那么使用`instanceof`是非常重要的,否則會得到一個`ClassCastException`異常。 一般,可能想要查找某種類型(比如要找三角形,并填充為紫色),這時可以輕松地使用`instanceof`來度量所有對象。舉個例子,假如你有一個類的繼承體系,描述了`Pet`(以及它們的主人,在后面一個例子中會用到這個特性)。在這個繼承體系中的每個`Individual`都有一個`id`和一個可選的名字。盡管下面的類都繼承自`Individual`,但是`Individual`類復雜性較高,因此其代碼將放在[附錄:容器](https://lingcoder.gitee.io/onjava8/#/./Appendix-Collection-Topics)中進行解釋說明。正如你所看到的,此處并不需要去了解`Individual`的代碼——你只需了解你可以創建其具名或不具名的對象,并且每個`Individual`都有一個`id()`方法,如果你沒有為`Individual`提供名字,`toString()`方法只產生類型名。 下面是繼承自`Individual`的類的繼承體系: ~~~ // typeinfo/pets/Person.java package typeinfo.pets; public class Person extends Individual { public Person(String name) { super(name); } } ~~~ ~~~ // typeinfo/pets/Pet.java package typeinfo.pets; public class Pet extends Individual { public Pet(String name) { super(name); } public Pet() { super(); } } ~~~ ~~~ // typeinfo/pets/Dog.java package typeinfo.pets; public class Dog extends Pet { public Dog(String name) { super(name); } public Dog() { super(); } } ~~~ ~~~ // typeinfo/pets/Mutt.java package typeinfo.pets; public class Mutt extends Dog { public Mutt(String name) { super(name); } public Mutt() { super(); } } ~~~ ~~~ // typeinfo/pets/Pug.java package typeinfo.pets; public class Pug extends Dog { public Pug(String name) { super(name); } public Pug() { super(); } } ~~~ ~~~ // typeinfo/pets/Cat.java package typeinfo.pets; public class Cat extends Pet { public Cat(String name) { super(name); } public Cat() { super(); } } ~~~ ~~~ // typeinfo/pets/EgyptianMau.java package typeinfo.pets; public class EgyptianMau extends Cat { public EgyptianMau(String name) { super(name); } public EgyptianMau() { super(); } } ~~~ ~~~ // typeinfo/pets/Manx.java package typeinfo.pets; public class Manx extends Cat { public Manx(String name) { super(name); } public Manx() { super(); } } ~~~ ~~~ // typeinfo/pets/Cymric.java package typeinfo.pets; public class Cymric extends Manx { public Cymric(String name) { super(name); } public Cymric() { super(); } } ~~~ ~~~ // typeinfo/pets/Rodent.java package typeinfo.pets; public class Rodent extends Pet { public Rodent(String name) { super(name); } public Rodent() { super(); } } ~~~ ~~~ // typeinfo/pets/Rat.java package typeinfo.pets; public class Rat extends Rodent { public Rat(String name) { super(name); } public Rat() { super(); } } ~~~ ~~~ // typeinfo/pets/Mouse.java package typeinfo.pets; public class Mouse extends Rodent { public Mouse(String name) { super(name); } public Mouse() { super(); } } ~~~ ~~~ // typeinfo/pets/Hamster.java package typeinfo.pets; public class Hamster extends Rodent { public Hamster(String name) { super(name); } public Hamster() { super(); } } ~~~ 我們必須顯式地為每一個子類編寫無參構造器。因為我們有一個帶一個參數的構造器,所以編譯器不會自動地為我們加上無參構造器。 接下來,我們需要一個類,它可以隨機地創建不同類型的寵物,同時,它還可以創建寵物數組和持有寵物的`List`。為了使這個類更加普遍適用,我們將其定義為抽象類: ~~~ // typeinfo/pets/PetCreator.java // Creates random sequences of Pets package typeinfo.pets; import java.util.*; import java.util.function.*; public abstract class PetCreator implements Supplier<Pet> { private Random rand = new Random(47); // The List of the different types of Pet to create: public abstract List<Class<? extends Pet>> types(); public Pet get() { // Create one random Pet int n = rand.nextInt(types().size()); try { return types().get(n).newInstance(); } catch (InstantiationException | IllegalAccessException e) { throw new RuntimeException(e); } } } ~~~ 抽象的`types()`方法需要子類來實現,以此來獲取`Class`對象構成的`List`(這是模板方法設計模式的一種變體)。注意,其中類的類型被定義為“任何從`Pet`導出的類型”,因此`newInstance()`不需要轉型就可以產生`Pet`。`get()`隨機的選取出一個`Class`對象,然后可以通過`Class.newInstance()`來生成該類的新實例。 在調用`newInstance()`時,可能會出現兩種異常。在緊跟`try`語句塊后面的`catch`子句中可以看到對它們的處理。異常的名字再次成為了一種對錯誤類型相對比較有用的解釋(`IllegalAccessException`違反了 Java 安全機制,在本例中,表示默認構造器為`private`的情況)。 當你創建`PetCreator`的子類時,你需要為`get()`方法提供`Pet`類型的`List`。`types()`方法會簡單地返回一個靜態`List`的引用。下面是使用`forName()`的一個具體實現: ~~~ // typeinfo/pets/ForNameCreator.java package typeinfo.pets; import java.util.*; public class ForNameCreator extends PetCreator { private static List<Class<? extends Pet>> types = new ArrayList<>(); // 需要隨機生成的類型名: private static String[] typeNames = { "typeinfo.pets.Mutt", "typeinfo.pets.Pug", "typeinfo.pets.EgyptianMau", "typeinfo.pets.Manx", "typeinfo.pets.Cymric", "typeinfo.pets.Rat", "typeinfo.pets.Mouse", "typeinfo.pets.Hamster" }; @SuppressWarnings("unchecked") private static void loader() { try { for (String name : typeNames) types.add( (Class<? extends Pet>) Class.forName(name)); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } static { loader(); } @Override public List<Class<? extends Pet>> types() { return types; } } ~~~ `loader()`方法使用`Class.forName()`創建了`Class`對象的`List`。這可能會導致`ClassNotFoundException`異常,因為你傳入的是一個`String`類型的參數,它不能在編譯期間被確認是否合理。由于`Pet`相關的文件在`typeinfo`包里面,所以使用它們的時候需要填寫完整的包名。 為了使得`List`裝入的是具體的`Class`對象,類型轉換是必須的,它會產生一個編譯時警告。`loader()`方法是分開編寫的,然后它被放入到一個靜態代碼塊里,因為`@SuppressWarning`注解不能夠直接放置在靜態代碼塊之上。 為了對`Pet`進行計數,我們需要一個能跟蹤不同類型的`Pet`的工具。`Map`是這個需求的首選,我們將`Pet`類型名作為鍵,將保存`Pet`數量的`Integer`作為值。通過這種方式,你就可以詢問:“有多少個`Hamster`對象?”我們可以使用`instanceof`來對`Pet`進行計數: ~~~ // typeinfo/PetCount.java // 使用 instanceof import typeinfo.pets.*; import java.util.*; public class PetCount { static class Counter extends HashMap<String, Integer> { public void count(String type) { Integer quantity = get(type); if (quantity == null) put(type, 1); else put(type, quantity + 1); } } public static void countPets(PetCreator creator) { Counter counter = new Counter(); for (Pet pet : Pets.array(20)) { // List each individual pet: System.out.print( pet.getClass().getSimpleName() + " "); if (pet instanceof Pet) counter.count("Pet"); if (pet instanceof Dog) counter.count("Dog"); if (pet instanceof Mutt) counter.count("Mutt"); if (pet instanceof Pug) counter.count("Pug"); if (pet instanceof Cat) counter.count("Cat"); if (pet instanceof EgyptianMau) counter.count("EgyptianMau"); if (pet instanceof Manx) counter.count("Manx"); if (pet instanceof Cymric) counter.count("Cymric"); if (pet instanceof Rodent) counter.count("Rodent"); if (pet instanceof Rat) counter.count("Rat"); if (pet instanceof Mouse) counter.count("Mouse"); if (pet instanceof Hamster) counter.count("Hamster"); } // Show the counts: System.out.println(); System.out.println(counter); } public static void main(String[] args) { countPets(new ForNameCreator()); } } ~~~ 輸出結果: ~~~ Rat Manx Cymric Mutt Pug Cymric Pug Manx Cymric Rat EgyptianMau Hamster EgyptianMau Mutt Mutt Cymric Mouse Pug Mouse Cymric {EgyptianMau=2, Pug=3, Rat=2, Cymric=5, Mouse=2, Cat=9, Manx=7, Rodent=5, Mutt=3, Dog=6, Pet=20, Hamster=1} ~~~ 在`countPets()`中,一個簡短的靜態方法`Pets.array()`生產出了一個隨機動物的集合。每個`Pet`都被`instanceof`檢測到并計算了一遍。 `instanceof`有一個嚴格的限制:只可以將它與命名類型進行比較,而不能與`Class`對象作比較。在前面的例子中,你可能會覺得寫出一大堆`instanceof`表達式很乏味,事實也是如此。但是,也沒有辦法讓`instanceof`聰明起來,讓它能夠自動地創建一個`Class`對象的數組,然后將目標與這個數組中的對象逐一進行比較(稍后會看到一種替代方案)。其實這并不是那么大的限制,如果你在程序中寫了大量的`instanceof`,那就說明你的設計可能存在瑕疵。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看