Odbicie tablicy w Javie: isArray vs. instanceof


177

Czy istnieje różnica preferencji lub zachowania między używaniem:

if(obj.getClass().isArray()) {}

i

if(obj instanceof Object[]) {}

?

Odpowiedzi:


203

W większości przypadków należy użyć rozszerzenia instanceof do sprawdzenia, czy obiekt jest tablicą operatora.

Ogólnie rzecz biorąc, typ obiektu jest testowany przed obniżeniem do określonego typu, który jest znany w czasie kompilacji. Na przykład, być może napisałeś jakiś kod, który może działać z Integer[]rozszerzeniem lub int[]. Chciałbyś chronić swoje obsady za pomocą instanceof:

if (obj instanceof Integer[]) {
    Integer[] array = (Integer[]) obj;
    /* Use the boxed array */
} else if (obj instanceof int[]) {
    int[] array = (int[]) obj;
    /* Use the primitive array */
} else ...

Na poziomie maszyny JVM instanceofoperator tłumaczy na konkretną „instancję” dokonuje kod bajtowy , który jest zoptymalizowany w większości implementacji JVM.

W rzadszych przypadkach możesz użyć odbicia, aby przejść przez graf obiektów nieznanych typów. W takich przypadkach isArray()metoda może być pomocna, ponieważ nie znasz typu komponentu w czasie kompilacji; możesz na przykład implementować jakiś mechanizm serializacji i być w stanie przekazać każdy składnik tablicy do tej samej metody serializacji, niezależnie od typu.

Istnieją dwa specjalne przypadki: odwołania o wartości null i odwołania do tablic pierwotnych.

Zerowe odwołanie spowoduje instanceofwynik false, podczas gdy isArrayzgłaszaNullPointerException .

Zastosowana do tablicy pierwotnej instanceofdaje wyniki, falsechyba że typ składnika w operandzie po prawej stronie dokładnie odpowiada typowi składnika. W przeciwieństwie do isArray()tego zwróci truedla dowolnego typu składnika.


7
Tak, ale jaką to różnicę? To brzmi dla mnie jak mikro-optymalizacja.
Michael Myers

2
@Dims Jeśli twierdzisz, że obj instanceof int[]daje falseto wynik po przypisaniu int[]do obj, to się mylisz.
erickson

4
Przepraszam, miałem na myśli, że obj instanceof Object[]ustępuje, falsejeśli Object obj = new int[7].
Przyciemnia

3
Tak, w Javie prymitywne typy danych nie są obiektami i nie rozszerzają się java.lang.Object, więc to ma sens. Ale instanceofnadal można go używać do testowania prymitywnych tablic.
erickson

4
-1: Ogólnie, ponieważ tablice pierwotne tablicami, isArray()należy używać wywołań . W bardzo nieogólnym, specjalnym przypadku posiadania tylko tablic obiektów, instanceofzapewnia alternatywę o wysokiej wydajności.
Sam Harwell

33

W tym drugim przypadku, jeśli obj jest null, nie otrzymasz wyjątku NullPointerException, ale fałsz.


8

Jeśli objjest typu int[]powiedz, to będzie mieć tablicę, Classale nie będzie instancją Object[]. Więc co chcesz zrobić obj. Jeśli masz zamiar to rzucić, idź z instanceof. Jeśli zamierzasz użyć odbicia, użyj .getClass().isArray().


4

getClass().isArray() jest znacznie wolniejszy na Sun Java 5 lub 6 JRE niż na IBM.

Do tego stopnia, że ​​korzystanie clazz.getName().charAt(0) == '['z Sun JVM jest szybsze.


10
Czy masz jakieś statystyki, studium przypadku lub inne dowody, do których możesz utworzyć link?
David Citron

4

Niedawno napotkałem problem podczas aktualizacji aplikacji Groovy z JDK 5 do JDK 6. Używanie isArray()nie powiodło się w JDK6:

MissingMethodException:
No signature of sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl.isArray() ...

Zmiana, aby instanceof Object[]to naprawić.


To nie ma sensu. isArrayjest metodą Class, nie Type, więc oczywiście jej GenericArrayTypeImplnie ma. I getClassnigdy nie możesz zwrócić nie- Class Type, więc ty (lub Groovy ??) musiałeś zrobić coś złego, aby to uzyskać, na przykład zakładając, że każdy Typejest Class.
kaqqao

3

Odbicie tablicy w języku Java jest stosowane w przypadkach, gdy nie masz instancji klasy, na której można by wykonać „instanceof”. Na przykład, jeśli piszesz pewien rodzaj struktury iniekcyjnej, która wstrzykuje wartości do nowej instancji klasy, takiej jak JPA, musisz użyć funkcji isArray ().

Pisałem o tym na blogu na początku grudnia. http://blog.adamsbros.org/2010/12/08/java-array-reflection/


2

Jeśli kiedykolwiek będziesz miał wybór między rozwiązaniem odblaskowym a nieodblaskowym, nigdy nie wybieraj rozwiązania odblaskowego (obejmującego obiekty klasy). Nie chodzi o to, że jest „źle” czy coś, ale wszystko, co wymaga refleksji, jest generalnie mniej oczywiste i mniej jasne.


No cóż, „instancja” to także rodzaj refleksji (lub przynajmniej introspekcji), ale rozumiem.
David Citron

Ponadto jest ogólnie wolniejszy.
Mad Physicist,

0

Nie ma różnicy w zachowaniu, które mogę znaleźć między tymi dwoma (poza oczywistym przypadkiem zerowym). Jeśli chodzi o preferowaną wersję, wybrałbym drugą. Jest to standardowa metoda w Javie.

Jeśli dezorientuje to czytelników twojego kodu (ponieważ String[] instanceof Object[]jest prawdą), możesz użyć pierwszego, aby być bardziej wyraźnym, jeśli recenzenci kodu będą o to pytać.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.