Dlaczego nie można przekazać zmiennej „Class” do elementu instanceof?

89

Dlaczego ten kod się nie kompiluje?

    public boolean isOf(Class clazz, Object obj){
        if(obj instanceof clazz){
            return true;
        }else{
            return false;
        }
    }

Dlaczego nie mogę przekazać zmiennej klasy do instanceof?

eric2323223
źródło

Odpowiedzi:

131

instanceofOperator pracuje nad typów referencyjnych, jak Integeri nie na obiektach, np new Integer(213). Prawdopodobnie chcesz coś takiego

clazz.isInstance(obj)

Uwaga dodatkowa: Twój kod będzie bardziej zwięzły, jeśli napiszesz

public boolean isOf(Class clazz, Object obj){
    return clazz.isInstance(obj)
}

Nie jestem jednak pewien, czy potrzebujesz już metody.

Robert Munteanu
źródło
Wiem, że kod jest całkowicie bezużyteczny, chcę tylko zademonstrować swoje zamieszanie :)
eric2323223
6
Integerto nie dosłownym klasa. Integer.classbyłby literałem klasy (patrz § 15.8.2 JLS: java.sun.com/docs/books/jls/third_edition/html/… ). instanceofOperator wykonuje "ReferenceType" (in nazwą typu), jak określono § 15.20.2 z JLS: java.sun.com/docs/books/jls/third_edition/html/...
Joachim Sauer
3
Używałbym, clazz.isInstance(obj)ponieważ obiekt został już dostarczony.
Donal Fellows
13

instanceofmoże być używany tylko z jawnymi nazwami klas (podanymi w czasie kompilacji). Aby przeprowadzić kontrolę działania , wykonaj następujące czynności:

clazz.isInstance(obj)

Ma to niewielką przewagę, clazz.isAssignableFrom(..)ponieważ lepiej radzi sobie ze sprawą obj == null.

Eyal Schneider
źródło
5

Jak wspominali inni, nie można przekazać zmiennej klasowej, instanceofponieważ zmienna klasowa odwołuje się do instancji Object , podczas gdy prawa ręka instanceofmusi być typem . Oznacza to, instanceofże nie oznacza „y jest wystąpieniem Obiektu x”, oznacza to „y jest wystąpieniem typu X”. Jeśli nie znasz różnicy między obiektem a typem, rozważ:

Object o = new Object();

Tutaj typ jest Objecti ojest odwołaniem do wystąpienia Object z tym typem. A zatem:

if(o instanceof Object)

jest ważny, ale

if(o instanceof o)

nie dlatego, że opo prawej stronie znajduje się Obiekt, a nie typ.

Bardziej specyficznie dla twojego przypadku, instancja klasy nie jest typem, jest to obiekt (który jest tworzony dla ciebie przez JVM). W twojej metodzie Classjest typem, ale clazzjest obiektem (cóż, odniesieniem do obiektu)

To, czego potrzebujesz, to sposób na porównanie obiektu z obiektem klasy. Okazuje się, że jest to popularny, więc to jest do was jako metody obiektu klasy: isInstance().

Oto dokumentacja Java dla isInstance, która wyjaśnia to lepiej:

public boolean isInstance(Object obj)

Określa, czy określony Object jest zgodny z przypisaniem z obiektem reprezentowanym przez tę klasę. Ta metoda jest dynamicznym odpowiednikiem operatora instanceof w języku Java. Metoda zwraca wartość true, jeśli określony argument Object ma wartość różną od null i może być rzutowany na typ referencyjny reprezentowany przez ten obiekt Class bez zgłaszania ClassCastException. W przeciwnym razie zwraca false.

W szczególności, jeśli ten obiekt Class reprezentuje zadeklarowaną klasę, ta metoda zwraca wartość true, jeśli określony argument Object jest instancją reprezentowanej klasy (lub dowolnej z jej podklas); w przeciwnym razie zwraca false. Jeśli ten obiekt Class reprezentuje klasę tablicy, ta metoda zwraca wartość true, jeśli określony argument Object można przekonwertować na obiekt klasy tablicy przez konwersję tożsamości lub rozszerzającą konwersję odwołania; w przeciwnym razie zwraca false. Jeśli ten obiekt Class reprezentuje interfejs, ta metoda zwraca wartość true, jeśli klasa lub dowolna nadklasa określonego argumentu Object implementuje ten interfejs; w przeciwnym razie zwraca false. Jeśli ten obiekt Class reprezentuje typ pierwotny, ta metoda zwraca false.

Parametry: obj - obiekt do sprawdzenia
Zwraca: true, jeśli obj jest instancją tej klasy
Od: JDK1.1

Rick Hanlon II
źródło
3

Po pierwsze instanceofwymaga, aby operand po prawej stronie był rzeczywistą klasą (np. obj instanceof ObjectLub obj instanceof Integer), a nie zmienną typu Class. Po drugie, popełniłeś dość powszechny błąd początkującego, którego naprawdę nie powinieneś robić ... następujący wzór:

if ( conditional_expression ) {
    powrót prawda;
} else {
    return false;
}

Powyższe można przełożyć na:

return conditional_expression ;

Zawsze należy przeprowadzać tę refaktoryzację, ponieważ eliminuje ona zbędną instrukcję if ... else. Podobnie wyrażenie można refaktoryzować do tego samego wyniku.return conditional_expression ? true : false;

Michael Aaron Safyan
źródło
2
To nie pomyłka. Może niezdarnie, ale w porządku. Może potrzebujesz dodatkowego kodu przed powrotem w dającej się przewidzieć przyszłości ...
Niesamowity styczeń