HOWTO · Java

Java Not InstanceOf

本教程演示如何在 Java 中否定 instanceof 關鍵字。

本頁內容

在 Java 中,沒有獨立的「非 instanceof」運算子。若要否定整個型別檢查,請寫成 !(object instanceof Type)。本指南會說明這個運算式的意義、繼承與 null 如何影響結果,以及如何用它篩選物件。

Java 中 instanceof 的檢查內容

instanceof 運算子會判斷非 null 物件是否可視為指定的參考型別:該型別可以是類別、父類別,或執行時類別相容的介面。例如,從子類別建立的物件,也會符合對其父類別及其實作介面的檢查。這個運算式會產生布林值,因此可用於 if 條件,也能與其他布林運算式組合。

左側必須是參考運算式,右側型別也必須與它相容。若兩個型別不可能有關聯,Java 會拒絕某些檢查。instanceof 不會轉換物件,只會判斷型別關係是否成立。檢查成功後可作為轉型前的判斷依據,但轉型本身是另一個操作。

如何否定 instanceof 檢查

將完整的型別檢查放在邏輯 NOT 運算子的括號內:!(object instanceof Type)。括號能清楚表示 ! 會反轉整個 instanceof 運算式的布林結果。物件符合 Type 時,內層檢查為 true,否定後的條件便是 false;物件不符合時,內層檢查為 false,否定後的條件便是 true。

你也可能會看到 object instanceof Type == false 這種寫法,但 !(object instanceof Type) 更直接地表達相同意思,也更容易閱讀。當你要處理的是不符合型別的情況時,可在 if 陳述式中使用否定形式。

範例:依型別篩選物件

這個完整範例會保留不是貓的動物並進行處理。程式會先為每個元素執行檢查,再於非貓的分支中使用該元素。

執行此範例:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

import java.util.List;

public class Main {
    interface Animal {}
    static class Dog implements Animal {}
    static class Cat implements Animal {}

    public static void main(String[] args) {
        List<Animal> animals = List.of(new Dog(), new Cat(), new Dog());
        for (Animal animal : animals) {
            if (!(animal instanceof Cat)) {
                System.out.println("Processing " + animal.getClass().getSimpleName());
            }
        }
    }
}
Processing Dog
Processing Dog

範例輸出會顯示兩行 Processing Dog。這是程式原有的英文標籤,為了保留範例內容而維持英文。

繼承與 null 如何影響結果

子類別的實例除了符合自身類別的 instanceof 檢查,也符合其父類別與所實作介面的檢查。因此,若物件是某個父類別之子類別的實例,否定對該父類別的檢查會得到 false。請謹慎選擇條件中的型別:檢查較廣泛的父類別,會排除比檢查特定子類別更多的物件。

運算式 null instanceof Type 的結果永遠是 false。因此,當 value 是 null 時,!(value instanceof Type) 會是 true。如果後續分支假設物件不是 null,或會呼叫它的方法,就必須另外處理這點;單靠否定型別檢查,無法確認該值不是 null。

何時使用否定的 instanceof 檢查

當不符合型別的情況正好描述你要執行的工作時,可使用 !(value instanceof Type),例如處理混合集合時略過某一種項目。讓條件緊鄰它所控制的分支,並選用能反映預期排除對象的明確型別。如果符合與不符合的兩種情況都需要大量處理邏輯,明確列出分支可能更容易理解。

負向檢查不會讓物件自動適合轉型成其他型別。轉型或呼叫型別專屬方法之前,請先確認這些操作所需的正向型別條件。如果值可能不存在,也要考慮 null 的行為。清楚的檢查有助於讀者檢視條件的含義,以及後續程式碼依賴的假設。