如何instanceof List <MyType>?


Answers:


49

这是不可能的,因为在泛型编译时会擦除数据类型。做到这一点的唯一可能方法是编写某种包装,该包装保存列表包含的类型:

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;
     }
}

谢谢,我想我只是将泛型类型传递到我要检查和检查这两个项目的函数中。
洛奇滑轮2012年

您能举例说明吗?
hirumal,

31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}

6
...还有一个空清单?思考?
Gewure

是的 这是可用于空列表的唯一选项。stackoverflow.com/questions/1942644/…–
Sathish

11
这个答案并不安全,因为即使0元素是MyType,其他元素也可能是其他类型。例如,也许列表被声明为ArrayList <Object>,然后添加了MyType,然后添加了String。
亚当Gawne该隐

@ AdamGawne-Cain这并不安全,但不幸的是,对于那些对列表不了解的人来说,这是唯一的解决方案。例如-我有一个value返回的局部变量Object,我需要检查-如果它是一个列表,如果是列表,请检查我的接口的列表类型instance。没有包装或参数化的类型在这里有用。
SocketByte

myList在哪里声明?
IgorGanapolsky '18年


6

如果您要检查object是的实例,则可以使用此实例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.
    }
}

2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}

1

如果要验证Object的List或Map值的引用是否是Collection的实例,只需创建所需List的实例并获取其类即可。

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());

什么是您的点setOfIntegerssetOfStrings
DanielM

@DanielM刚刚更新了示例。它必须使用这些引用!谢谢!
Marcello de Sales

1

如果不能用泛型将其包装(@Martijn的答案),则最好在不进行强制转换的情况下传递它,以避免重复的列表迭代(检查第一个元素的类型不能保证任何内容)。我们可以在迭代列表的代码段中强制转换每个元素。

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 );
    }
}

0

您可以使用伪造的工厂来包含许多方法,而不是使用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);
    }
}

0

这里的主要问题是集合不会在定义中保留类型。这些类型仅在运行时可用。我想出了一个测试复杂集合的函数(尽管它有一个约束)。

检查对象是否为通用集合的实例。为了表示一个集合,

  • 永远不上课 false
  • 一个类,它不是一个集合,并返回instanceof评估结果
  • 为了表示一个List或者Set,列表类型随之而来的如{列表,整数冲List<Integer>
  • Map接下来,要表示键和值类型,例如{Map,String,Integer}Map<String, Integer>

使用相同的规则可以生成更复杂的用例。例如,为了表示List<Map<String, GenericRecord>>,可以将其称为

    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);

请注意,此实现不支持Map中的嵌套类型。因此,键和值的类型应该是一个类,而不是一个集合。但是添加它并不难。

    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;
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.