【问题标题】:how to determine the Class inside a Collection in Java?如何确定Java中集合内的类?
【发布时间】:2011-10-25 06:25:56
【问题描述】:

如何判断 Collection 中的类是什么类型?我需要以不同于处理复杂类型的方式处理简单数据类型,因此我必须知道包含的类。目前,我必须遍历集合以找出听起来不正确的类。这个link 很有帮助,但没有完全解决我的问题。基本上,这里有以下问题: 1.如何确定集合内的类? 2. 如何判断对象是java包装类(Integer、String、Date等)还是专有类(Student、Vehicle等)。

谢谢 贾巴瓦巴

entity = new SomeObject();
Class entityClass = entity.getClass();
for (Method method : entityClass.getDeclaredMethods()) {
  Class<?> returnType = method.getReturnType();
  if (returnType != null) {
    if (returnType.isPrimitive() || (returnType.getName().startsWith("java.lang.")) || (returnType == java.util.Date.class)) {
      // handling primitive and wrapper classes
      handleScalar(method);
    } else if (Collection.class.isAssignableFrom(returnType)) {
      Collection collection = (Collection) method.invoke(entity);
      if (collection == null || collection.isEmpty()) {
        continue;
      }
      for (Object value : collection) {
        if (value.getClass().getName().startsWith("java.lang.") || (value.getClass() == java.util.Date.class)) {
          handleSimpleVector(method);
          // no need to go through all the simple values
          continue;
        } else {
          // Each 'value' is itself a complex object.
          handleComplexObject(method);
        }
      }
    } else if (<return-type-is-an-Array>){
      // do something similar as the above.
    }
  }
}

【问题讨论】:

  • 根据您发布的代码,您已经成功了。那么你试图完成什么,你在什么时候卡住了?
  • @Platvoet。我试图区分 return 类型: (a) public long getDistance(); (b) 公共列表 getCounts(); (c) public List getCars(); (d) public Long[] getSizes();因为我正在为 Lucene/Solr 编写一个包装器,并且我需要知道访问器的返回类型来决定我应该使用哪种 Solr 字段。
  • 你想要完成什么?我觉得有更好的方法,而您只是使用了错误的工具。
  • 让我重新表述一下,就像 Amir 一样,我想知道这段代码的目的是什么。为什么需要区分这些方法?可能会有更适合您需求的不同方法。
  • 所以您基本上只想在 Lucene 中存储任何类?在这种情况下,您可能会考虑使用 java 的可序列化系统。提供您自己的 ObjectInputStream 和 ObjectOutputStream。

标签: java


【解决方案1】:

1) 如果它不是一个通用类型的集合,你根本就不能。非类型化集合可以包含任何对象类型的混合。

如果您正在处理(非空)类型的集合,那么您可以在运行时确定其内容的类,例如由

Collection<?> coll = ...
if (coll.isEmpty())
    throw new BadLuckException();
Object representative = coll.iterator().next();
Class<?> typeOfContent = representative.getClass();
//apply your cases on this Class object

没有其他方法可以在运行时确定泛型类型信息,因为泛型类型纯粹是编译时信息。

2) Date 不是包装类 - 原始类及其包装是:

  • 短/短
  • 整数/整数
  • 长/长
  • 字节/字节
  • 字符/字符
  • 双/双
  • 浮动/浮动
  • 布尔值/布尔值

您可以使用Class#isPrimitive 确定您的类是否是原始类。但是请注意,这只会确定一个对象是否真的是原始的,它不会确定您是否正在处理一个自动装箱的值:

System.out.println(Integer.class.isPrimitive()); // -> false

但是,每个包装类都声明了一个名为“TYPE”的字段,该字段表示它所包装的原始类。所以你可以像这样检查一个类是否是一个包装类:

public static boolean isWrapperClass(Class<?> clazz) {
    try {
        clazz.getDeclaredField("TYPE");
        return true;
    catch (NoSuchFieldException ex) {
        return false;
    }
}

【讨论】:

  • 感谢您确认我的怀疑。比上面显示的更优雅的方式来确定包装器/原始类与非标准类怎么样?
  • 查看我的编辑 - 恐怕除了显式比较类的丑陋方法之外别无他法。
【解决方案2】:

你为什么不能这样做?

Collection c = new ArrayList();
c.add("Hi");
Iterator i = c.iterator();
Object v = i.hasNext()? i.next() : null;
if(v != null) {
    System.out.println(v.getClass().getName());
}

更新:

假设它是一个同质集合。希望我正确理解了您的问题。

【讨论】:

  • 我已经在示例代码中这样做了。我确实想遍历泛型集合以找出包含的类类型。
【解决方案3】:

查看您的示例(整数、字符串、日期等),我只需创建一个包含您想要以不同方式处理的所有类型的集合,然后检查值类型是否在此集合中。您仍然需要遍历集合元素或假设集合的所有元素都属于同一类型。

【讨论】:

    【解决方案4】:

    无法在运行时确定未知集合的类型参数。 JVM 在运行时根本不会保存这些信息。

    【讨论】:

    • 当然可以。您可以对任何对象执行 getClass。我认为你的意思是泛型类型。部分正确。
    • 您可以检测到集合本身的 erased 类型,但无法获取其泛型类型 arguments(请注意答案?)。您可以尝试查看元素本身,但如果没有元素或它们都是空值,那么您将一无所获。
    【解决方案5】:

    我认为您可以像这样使用 instanceof 关键字:

    if(s instanceof java.lang.String)
    {
    
    }
    

    Link to examples

    【讨论】:

    • 这需要检查您要查找的每个案例,因此可能不实用
    • 但是我必须遍历收集项,这正是我想要避免的。
    • 或者这可能正是你想要避免的……我的错!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    相关资源
    最近更新 更多