jak instancja listy <MyType>?

Odpowiedzi:

49

Nie jest to możliwe, ponieważ wymazywanie typu danych w czasie kompilacji typów generycznych. Jedynym możliwym sposobem na zrobienie tego jest napisanie pewnego rodzaju opakowania, które przechowuje typ przechowywanej listy:

public class GenericList <T> extends ArrayList<T>
{
     private Class<T> genericType;

     public GenericList(Class<T> c)
     {
          this.genericType = c;
     }

     public Class<T> getGenericType()
     {
          return genericType;
     }
}
Martijn Courteaux
źródło
Dzięki, myślę, że po prostu przekażę typ ogólny do funkcji, którą wywołuję, aby sprawdzić i sprawdzić obie pozycje.
Rocky Pulley
Czy możesz podać przykład
Thirumal
31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}
Sathish
źródło
7
... i na pustą listę? Refleksje?
Gewure
Yeap. To jedyna opcja dostępna dla pustej listy. stackoverflow.com/questions/1942644/…
Sathish
12
Ta odpowiedź nie jest bezpieczna, ponieważ nawet jeśli element 0 jest MyType, pozostałe elementy mogą być innego typu. Na przykład, być może lista została zadeklarowana jako ArrayList <Object>, następnie dodano MyType, a następnie dodano String.
Adam Gawne-Cain,
@ AdamGawne-Cain To nie jest bezpieczne, ale niestety jedyne rozwiązanie dla osób NIE wiedzących zbyt wiele o liście. Na przykład - mam zmienną lokalną, valuektóra zwraca Objecti muszę sprawdzić - jeśli jest to lista, jeśli jest, sprawdź, czy typ listy jest instancją mojego interfejsu. Żaden rodzaj opakowania lub sparametryzowany nie jest tutaj przydatny.
SocketByte
Gdzie jest zadeklarowana myList ?
Igor Ganapolsky
9

Prawdopodobnie będziesz musiał użyć refleksji, aby sprawdzić ich typy. Aby uzyskać typ listy: Pobierz ogólny typ java.util.List

evanwong
źródło
2
O ile wiem, działa to tylko w przypadku pól, ale +1 za wzmiankę o tym.
Tim Pote,
6

Można tego użyć, jeśli chcesz sprawdzić, czy objectjest to wystąpienie List<T>, które nie jest puste:

if(object instanceof List){
    if(((List)object).size()>0 && (((List)object).get(0) instanceof MyObject)){
        // The object is of List<MyObject> and is not empty. Do something with it.
    }
}
Ivo Stoyanov
źródło
2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}
dlaagniechy
źródło
1

Jeśli sprawdzasz, czy odwołanie do wartości listy lub mapy obiektu jest instancją kolekcji, po prostu utwórz instancję wymaganej listy i pobierz jej klasę ...

Set<Object> setOfIntegers = new HashSet(Arrays.asList(2, 4, 5));
assetThat(setOfIntegers).instanceOf(new ArrayList<Integer>().getClass());

Set<Object> setOfStrings = new HashSet(Arrays.asList("my", "name", "is"));
assetThat(setOfStrings).instanceOf(new ArrayList<String>().getClass());
Marcello de Sales
źródło
Jaki jest sens twojego setOfIntegersi setOfStrings?
DanielM,
@DanielM właśnie zaktualizował przykład. Musi używać tych odniesień! Dzięki!
Marcello de Sales,
1

Jeśli nie można tego opakować generycznymi (odpowiedź @ Martijn), lepiej przekazać to bez rzutowania, aby uniknąć powtarzających się iteracji listy (sprawdzenie typu pierwszego elementu nic nie gwarantuje). Możemy rzutować każdy element z fragmentu kodu, w którym iterujemy listę.

Object attVal = jsonMap.get("attName");
List<Object> ls = new ArrayList<>();
if (attVal instanceof List) {
    ls.addAll((List) attVal);
} else {
    ls.add(attVal);
}

// far, far away ;)
for (Object item : ls) {
    if (item instanceof String) {
        System.out.println(item);
    } else {
        throw new RuntimeException("Wrong class ("+item .getClass()+") of "+item );
    }
}
kinjelom
źródło
0

Możesz użyć fałszywej fabryki, aby dołączyć wiele metod zamiast używać instanceof:

public class Message1 implements YourInterface {
   List<YourObject1> list;
   Message1(List<YourObject1> l) {
       list = l;
   }
}

public class Message2 implements YourInterface {
   List<YourObject2> list;
   Message2(List<YourObject2> l) {
       list = l;
   }
}

public class FactoryMessage {
    public static List<YourInterface> getMessage(List<YourObject1> list) {
        return (List<YourInterface>) new Message1(list);
    }
    public static List<YourInterface> getMessage(List<YourObject2> list) {
        return (List<YourInterface>) new Message2(list);
    }
}
LeLe
źródło
0

Głównym problemem jest to, że kolekcje nie zachowują typu w definicji. Typy są dostępne tylko w czasie wykonywania. Wymyśliłem funkcję do testowania złożonych kolekcji (ma ona jednak jedno ograniczenie).

Sprawdź, czy obiekt jest instancją kolekcji ogólnej. Aby reprezentować kolekcję,

  • Żadnych zajęć, zawsze false
  • Jedna klasa nie jest zbiorem i zwraca wynik instanceofoceny
  • Aby przedstawić Listlub Set, typ listy jest następny, np. {List, Integer} dlaList<Integer>
  • Aby przedstawić a Map, klucz i typy wartości są następne, np. {Map, String, Integer} forMap<String, Integer>

Bardziej złożone przypadki użycia można generować przy użyciu tych samych reguł. Na przykład, aby przedstawić List<Map<String, GenericRecord>>, można go nazwać jako

    Map<String, Integer> map = new HashMap<>();
    map.put("S1", 1);
    map.put("S2", 2);
    List<Map<String, Integer> obj = new ArrayList<>();
    obj.add(map);
    isInstanceOfGenericCollection(obj, List.class, List.class, Map.class, String.class, GenericRecord.class);

Należy zauważyć, że ta implementacja nie obsługuje typów zagnieżdżonych w Map. Stąd typ klucza i wartości powinien być klasą, a nie kolekcją. Ale nie powinno być trudno go dodać.

    public static boolean isInstanceOfGenericCollection(Object object, Class<?>... classes) {
        if (classes.length == 0) return false;
        if (classes.length == 1) return classes[0].isInstance(object);
        if (classes[0].equals(List.class))
            return object instanceof List && ((List<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Set.class))
            return object instanceof Set && ((Set<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Map.class))
            return object instanceof Map &&
                    ((Map<?, ?>) object).keySet().stream().allMatch(classes[classes.length - 2]::isInstance) &&
                    ((Map<?, ?>) object).values().stream().allMatch(classes[classes.length - 1]::isInstance);
        return false;
    }
Iraj Hedayati
źródło