【问题标题】:How to check if an Object is a Collection Type in Java?如何检查对象是否是Java中的集合类型?
【发布时间】:2011-02-08 17:55:31
【问题描述】:

通过使用java反射,我们可以很容易地知道一个对象是否是一个数组。判断一个对象是否为集合(Set、List、Map、Vector...)的最简单方法是什么?

【问题讨论】:

    标签: java


    【解决方案1】:
    if (x instanceof Collection<?>){
    }
    
    if (x instanceof Map<?,?>){
    }
    

    【讨论】:

    • 请注意其中的?。您无法访问已擦除的组件类型。如果您需要知道集合中可能包含哪些类型的对象,则需要查看元素本身。
    • 在没有元素的情况下,如何找出集合中有哪些对象?
    【解决方案2】:

    更新:这里有两种可能的情况:

    1. 您正在确定一个对象是否是一个集合;

    2. 您正在确定一个类是否是一个集合。

    解决方案略有不同,但原理相同。您还需要定义究竟是什么构成了“集合”。实现 CollectionMap 将涵盖 Java 集合。

    解决方案 1:

    public static boolean isCollection(Object ob) {
      return ob instanceof Collection || ob instanceof Map;
    }
    

    解决方案 2:

    public static boolean isClassCollection(Class c) {
      return Collection.class.isAssignableFrom(c) || Map.class.isAssignableFrom(c);
    }
    

    (1)也可以按照(2)来实现:

    public static boolean isCollection(Object ob) {
      return ob != null && isClassCollection(ob.getClass());
    }
    

    我认为这两种方法的效率不会有很大的不同。

    【讨论】:

    • 因为这个任务可以在没有“instanceof”的情况下解决
    • @den bardmadym 为什么你不想使用 instaceof?
    • 我相信 instanceof 比 isAssignableFrom 更高效,不是吗?
    • 我只会在必要时使用反射(isAssignableFrom),即在编译时不知道要测试的类。否则,一个简单的 instanceof 更容易输入和阅读,恕我直言。
    • @duduamar 可能你是对的(应该看看字节码)。肯定 isAssignableFrom 的使用不能胜过 instanceof
    【解决方案3】:

    既然你在问题中提到了反思;

    boolean isArray = myArray.getClass().isArray();
    boolean isCollection = Collection.class.isAssignableFrom(myList.getClass());
    boolean isMap = Map.class.isAssignableFrom(myMap.getClass());
    

    【讨论】:

    • 最佳答案在这里 IMO
    • 您也可以使用它,如果 myArray 引用为空,您将获得 NPE。因此需要检查 null 作为结果。通过instanceof 进行检查是没有必要的。见stackoverflow.com/questions/2950319/…
    • @Alexandr:其他答案都没有else 子句或检查null。至少有了这个答案,你不得不考虑 null 选项。
    • @Foumpie,obj instanceof Collection。我从来没有得到过NPE。我不需要检查空值。如果obj 为空,此语句的结果将为假。通过反射,您无需明确检查即可获得 NPE。
    【解决方案4】:

    Java 方便地使用 instanceof 运算符 (JLS 15.20.2) 来测试给定对象是否属于给定类型。

     if (x instanceof List<?>) {   
        List<?> list = (List<?>) x;
        // do something with list
     } else if (x instanceof Collection<?>) {
        Collection<?> col = (Collection<?>) x;
        // do something with col
     }
    

    这里应该提到一件事:在这些类型的结构中检查正确的顺序很重要。你会发现,如果你在上面的 sn-p 中交换了检查的顺序,代码仍然可以编译,但是将不再工作。那就是下面的代码不起作用:

     // DOESN'T WORK! Wrong order!
     if (x instanceof Collection<?>) {
        Collection<?> col = (Collection<?>) x;
        // do something with col
     } else if (x instanceof List<?>) { // this will never be reached!
        List<?> list = (List<?>) x;
        // do something with list
     }
    

    问题是List&lt;?&gt;是-aCollection&lt;?&gt;,所以它会通过第一个测试,而else意味着它永远不会达到第二个测试。 你必须从最具体到最一般的类型进行测试

    【讨论】:

    • 地图不扩展集合。
    • @Thilo:脑残;修改为List。重点仍然存在。
    【解决方案5】:

    测试对象是否实现java.util.Collectionjava.util.Map。 (Map 必须单独测试,因为它不是Collection 的子接口。)

    【讨论】:

      【解决方案6】:

      您是否考虑过使用 @987654321@ ? 比如,说

      if(myObject instanceof Collection) {
           Collection myCollection = (Collection) myObject;
      

      虽然不是那种纯粹的 OOP 风格,但它主要用于所谓的“类型升级”。

      【讨论】:

      • 像我这样的老开发人员有时倾向于依赖 java1.5 之前的符号来处理像这样的不可编译示例,尤其是当泛型符号没有增加任何价值时。
      • 增加的价值是您明确声明类型未知。无法以 1.5 之前的符号表示此信息。
      • @Max 表现得像个复活者?我知道你在搜索什么点 ;-) 无论如何,在 Java 5+ 中,CollectionCollection&lt;?&gt; 是等价的,因为它们都将包含 Object 实例。因此,泛型在这里没有附加价值。
      猜你喜欢
      • 2011-01-24
      • 2020-02-24
      • 1970-01-01
      • 1970-01-01
      • 2018-01-03
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多