如何使用instanceof判断List<MyType>类型?

110

我该如何使这种事情起作用?我可以检查(obj instanceof List<?>),但无法检查(obj instanceof List<MyType>)。是否有办法解决这个问题?


1
请参阅http://docs.oracle.com/javase/tutorial/java/generics/erasure.html。 - Paul Bellora
1
可能是重复的问题:无法对参数化类型ArrayList<Foo>执行instanceof检查 - Paul Bellora
9个回答

57

这是不可能的,因为泛型在编译时会擦除数据类型。唯一可能的方法是编写某种包装器,以保存列表所持有的类型:

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

谢谢,我想我会将通用类型传递到我要调用的函数中进行检查,并检查两个项目。 - Rocky Pulley
3
你能举个例子详细说明吗? - Thirumal

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

8
...而对于空列表呢?反射? - Gewure
是的,这是空列表可用的唯一选项。 - Sats
21
这个答案不安全,因为即使第 0 个元素是 MyType,其他元素可能会是其他类型。例如,也许这个列表被声明为 ArrayList<Object>,然后添加了一个 MyType,再加上一个 String。 - Adam Gawne-Cain
@AdamGawne-Cain 这并不安全,但对于那些不太了解列表的人来说,这是唯一的解决方案。例如 - 我有一个返回 Object 的本地变量 value,我需要检查 - 如果它是一个列表,如果是,检查列表类型是否是我的接口的实例。在这里,没有包装器或参数化类型是有用的。 - SocketByte
myList 被声明在哪里? - IgorGanapolsky
1
如果列表为空怎么办?!这个答案并没有回答问题,甚至是误导性的,我不知道它是如何得到22个赞的!? - Mehdi

10

如果您想检查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.
    }
}

9

2
据我所知,这仅适用于字段,但因提及而加1。 - Tim Pote

5
    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 DeSales

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评估的结果
  • 要表示ListSet,则列表类型紧随其后,例如{List,Integer}表示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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接