Bu tür şeyleri nasıl çalıştırabilirim? Kontrol edebilirim (obj instanceof List<?>)
ama yapamayabilirim (obj instanceof List<MyType>)
. Bunu yapmanın bir yolu var mı?
Bu tür şeyleri nasıl çalıştırabilirim? Kontrol edebilirim (obj instanceof List<?>)
ama yapamayabilirim (obj instanceof List<MyType>)
. Bunu yapmanın bir yolu var mı?
Yanıtlar:
Bu mümkün değildir çünkü jeneriklerin derleme zamanında veri türü silinir. Bunu yapmanın tek olası yolu, listenin içerdiği türü tutan bir tür sarmalayıcı yazmaktır:
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;
}
}
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
// MyType object
}
value
dönen bir yerel değişkenim var Object
ve kontrol etmem gerekiyor - bu bir liste ise, eğer öyleyse, arayüzümün liste tipi örneğinin olup olmadığını kontrol et. Burada hiçbir sarmalayıcı veya parametrik tip yararlı değildir.
Türlerini kontrol etmek için muhtemelen yansıma kullanmanız gerekir. Listenin türünü almak için: java.util.List'in genel türünü alın
Bu , boş olmayan object
örneğinin olup olmadığını kontrol etmek isterseniz kullanılabilir List<T>
:
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.
}
}
if (list instanceof List && ((List) list).stream()
.noneMatch((o -> !(o instanceof MyType)))) {}
Bir Nesnenin Liste veya Harita değerinin referansının Koleksiyonun bir örneği olup olmadığını doğruluyorsanız, gerekli Listenin bir örneğini oluşturun ve sınıfını alın ...
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());
setOfIntegers
ve setOfStrings
?
Eğer bu jeneriklerle sarılamıyorsa (@ Martijn'in cevabı) gereksiz liste yinelemesinden kaçınmak için çevrim yapmadan geçmek daha iyidir (ilk elemanın türünün kontrol edilmesi hiçbir şeyi garanti etmez). Her bir öğeyi listeyi yinelediğimiz kod parçasına yerleştirebiliriz.
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 );
}
}
İnstanceof kullanmak yerine birçok yöntemi dahil etmek için sahte bir fabrika kullanabilirsiniz:
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);
}
}
Buradaki en büyük endişe, koleksiyonların türü tanımda tutmamasıdır. Türler yalnızca çalışma zamanında mevcuttur. Karmaşık koleksiyonları test etmek için bir işlev buldum (yine de bir kısıtlaması var).
Nesnenin genel bir koleksiyonun bir örneği olup olmadığını kontrol edin. Bir koleksiyonu temsil etmek için,
false
instanceof
değerlendirme sonucunu döndürürList
veya temsil etmek için Set
, listenin türü sonra gelir örn. {Liste, Tamsayı} içinList<Integer>
Map
, anahtar ve değer türleri daha sonra gelir, ör. {Eşleme, Dize, Tamsayı} içinMap<String, Integer>
Aynı kurallar kullanılarak daha karmaşık kullanım durumları oluşturulabilir. Örneğin temsil etmek için List<Map<String, GenericRecord>>
şu şekilde adlandırılabilir:
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);
Bu uygulamanın Haritadaki iç içe geçmiş türleri desteklemediğini unutmayın. Bu nedenle, anahtarın ve değerin türü bir koleksiyon değil, bir sınıf olmalıdır. Ama eklemek zor olmamalı.
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;
}