Jak sprawdzić, czy obiekt jest tablicą bez użycia odbicia?

99

Jak sprawdzić w Javie, czy obiekt jest tablicą bez użycia odbicia? Jak mogę iterować przez wszystkie elementy bez używania refleksji?

Używam Google GWT, więc nie mogę używać odbicia :(

Bardzo chciałbym zaimplementować następujące metody bez użycia refelekcji:

private boolean isArray(final Object obj) {
  //??..
}

private String toString(final Object arrayObject) {
  //??..
}

BTW: nie chcę też używać JavaScript, aby móc go używać w środowiskach innych niż GWT.

edbras
źródło

Odpowiedzi:

248

Możesz użyć Class.isArray()

public static boolean isArray(Object obj)
{
    return obj!=null && obj.getClass().isArray();
}

Działa to zarówno w przypadku tablic obiektów, jak i typów pierwotnych.

Spójrz na toString Arrays.toString. Będziesz musiał sprawdzić typ tablicy i wywołać odpowiednią toStringmetodę.

Steve Kuo
źródło
1
Warto dodać, że możesz sprawdzić typ tablicy za pomocą obj.getClass().getComponentType().
Steve Chambers
68

Możesz użyć instanceof.

Operator porównania typów JLS 15.20.2 instanceof

 RelationalExpression:
    RelationalExpression instanceof ReferenceType

W czasie wykonywania wynik działania instanceofoperatora jest truetaki, że wartość RelationalExpression nie jest różna, nulla odwołanie może zostać rzutowane na typ ReferenceType bez podnoszenia wartości ClassCastException. W przeciwnym razie wynikiem jest false.

Oznacza to, że możesz zrobić coś takiego:

Object o = new int[] { 1,2 };
System.out.println(o instanceof int[]); // prints "true"        

Trzeba by sprawdzić, czy przedmiot jest instanceof boolean[], byte[], short[], char[], int[], long[], float[], double[], lub Object[], jeśli chcesz, aby wykryć wszystkie rodzaje tablic.

Ponadto an int[][]to an instanceof Object[], więc w zależności od tego, jak chcesz obsługiwać tablice zagnieżdżone, może to się skomplikować.

W przypadku toString, java.util.Arraysma toString(int[])i inne przeciążenia, których możesz użyć. Ma również deepToString(Object[])dla tablic zagnieżdżonych.

public String toString(Object arr) {
   if (arr instanceof int[]) {
      return Arrays.toString((int[]) arr);
   } else //...
}

Będzie to bardzo powtarzalne (ale nawet java.util.Arraysbardzo powtarzalne ), ale tak jest w Javie z tablicami.

Zobacz też

smary wielogenowe
źródło
Dzięki, nie zdawałem sobie sprawy, że to takie proste. Myśli insstanceof nie mogą być użyte bezpośrednio z T [] :(
edbras
2
BTW: Zauważyłem także inny fajny sposób na sprawdzenie, czy coś jest tablicą Class.isArray () (używaną w Arrays.deepToString ()).
edbras
@edbras: tak, to właśnie powiedział poniżej Steve Kuo. Moje rozwiązanie wykorzystuje konstrukcję czysto lingwistyczną zamiast wywołania API.
polygenelubricants
Działa dobrze, nie używam tylko instanceof, ale getClass jako porównania. Coś w rodzaju: if (array.getClass == int []. Class) {Arrays.toString ((int []) tablica); } Dzięki wszystkim ..
edbras
@edbras: Tak to się java.util.Arraysdzieje, tak. Widzę, że czytałeś kod, do którego utworzyłem łącze.
poligenelubricants
35

Dostęp do każdego elementu tablicy można uzyskać osobno, używając następującego kodu:

Object o=...;
if ( o.getClass().isArray() ) {
    for(int i=0; i<Array.getLength(o); i++){
        System.out.println(Array.get(o, i));
    }
}

Zauważ, że nie trzeba wiedzieć, jakiego rodzaju jest to podstawowa tablica, ponieważ zadziała to dla każdej tablicy.

user1928596
źródło
2
isArray()został już odpowiednio uwzględniony w odpowiedziach zamieszczonych 4 lata wcześniej.
Jason C
15
Ta odpowiedź jest świetna, ponieważ pokazuje nam, jak uzyskać rozmiar tablicy i pobrać element bez wiedzy o jego typie zawartości. Jestem pewien, że większość ludzi nigdy wcześniej nie pisała takiego kodu.
Christopher Yang,
@MaartenBodewes - skorzystałbym z tego linku, aby zdecydować, co oznacza „niewykorzystywanie refleksji” dla GWT.
Stephen C
10

Nie ma relacji podtypów między tablicami typu pierwotnego lub między tablicą typu pierwotnego a tablicą typu referencyjnego. Zobacz JLS 4.10.3 .

Dlatego poniższy kod jest niepoprawny jako test służący do sprawdzenia, czy objjest to tablica dowolnego rodzaju :

// INCORRECT!
public boolean isArray(final Object obj) {
    return obj instanceof Object[];
}

W szczególności nie działa, jeśli objjest 1-D tablicą prymitywów. (Działa to jednak w przypadku tablic prymitywnych o wyższych wymiarach, ponieważ wszystkie typy tablic są podtypami Object. Ale w tym przypadku jest to dyskusyjne).

Używam Google GWT, więc nie mogę używać odbicia :(

Najlepsze rozwiązanie (w isArrayczęści tablicowej pytania) zależy od tego, co liczy się jako „użycie odbicia”.

  • W GWT wywołanie obj.getClass().isArray()nie liczy się jako użycie odbicia 1 , więc jest to najlepsze rozwiązanie.

  • W przeciwnym razie najlepszym sposobem ustalenia, czy obiekt ma typ tablicowy, jest użycie sekwencji instanceofwyrażeń.

    public boolean isArray(final Object obj) {
        return obj instanceof Object[] || obj instanceof boolean[] ||
           obj instanceof byte[] || obj instanceof short[] ||
           obj instanceof char[] || obj instanceof int[] ||
           obj instanceof long[] || obj instanceof float[] ||
           obj instanceof double[];
    }
  • Możesz także spróbować pograć z nazwą klasy obiektu w następujący sposób, ale wywołanie obj.getClass()graniczy z refleksją.

    public boolean isArray(final Object obj) {
        return obj.getClass().toString().charAt(0) == '[';
    }

1 - Dokładniej, Class.isArraymetoda jest wymieniona jako obsługiwana przez GWT na tej stronie .

Stephen C.
źródło
0

Możesz utworzyć klasę narzędziową, aby sprawdzić, czy klasa reprezentuje kolekcję , mapę lub tablicę

  public static boolean isCollection(Class<?> rawPropertyType) {
        return Collection.class.isAssignableFrom(rawPropertyType) || 
               Map.class.isAssignableFrom(rawPropertyType) || 
               rawPropertyType.isArray();
 }
Lucas Pires
źródło
0

Po prostu obj instanceof Object[](przetestowane w JShell).

Sina Madani
źródło