【问题标题】:Checking Java Collection Generic Type for an Empty Collection检查空集合的 Java 集合泛型类型
【发布时间】:2012-09-08 12:02:25
【问题描述】:

我要实现以下功能:

public boolean checkType(Vector<?> vec)
{
  // return true if its Vector<Integer> and false otherwise
}

如何检查矢量元素类型? 请注意向量可能为空,因此我无法检查第一个元素是“instanceof”整数还是字符串...

编辑:

嗯,我有一些想法,我不知道它是否会起作用

我可以实现如下的checkType函数吗:

public <T> boolean checkType(Vector<T> vec)
{
  // return true if T is Integer and false otherwise
}

是否可以检查 T 是否为整数?!

提前致谢

【问题讨论】:

  • 如果向量可能为空,我认为检查泛型类型没有意义
  • 如果 vec 是 Vector&lt;Long&gt;,返回什么?真、假、半真?老实说,这不是一个很好的设计。
  • @anand,我只是想知道是否有办法在不检查向量中随机元素的类型的情况下检查泛型类型...
  • @Natix,如果不是 Vector,您可以返回 false ...这不是重点...您可以首先检查泛型类型吗?

标签: java


【解决方案1】:

泛型类型参数由于type erasure而在运行时不可恢复(某些特殊情况除外)。这意味着在运行时,Vector&lt;Integer&gt;Vector&lt;String&gt; 都只是 Vectors,它们的元素只是 Object 引用。

只有各个元素的实际运行时类(如您所指出的那样,可以通过 instanceof 检查发现)才构成元素类型的概念,否则 Vector 本身不知道它的元素类型是什么。

所以基本上,任何类型的空向量都等于任何其他类型的 empty 向量。像这样投射它甚至是安全的:

Vector<String> noStrings = (Vector<String>) new Vector<Integers>();

但是有一个问题,因为虽然你可以说 empty 向量符合任何所需的元素类型,但这个说法只有只要向量保持为空。因为如果你这样做:

Vector<Integer> ints = new Vector<Integer>(); // empty
Vector<String> strings = (Vector<String>) ints; // unchecked warning, but still possibly ok
ints.add(1); // here comes trouble
String s = strings.get(1); // oh oh, ClassCastException

编辑:

回答你第二个问题:不,不可能这样写:

public <T> boolean checkType(Vector<T> vec) {
    return T instanceof Integer; // impossible
    return T == Integer; // impossible
    return T.class == Integer.class // impossible
    return vec instanceof (Vector<Integer>); // impossible
}

但是您可以编写一个使用类标记作为输入参数的方法:

static <T> boolean checkElementType(Collection<?> collection, Class<T> elementType) {
    for (Object object : collection) {
        if (!elementType.isAssignableFrom(object.getClass())) {
            return false;
        }
    }
    return true;
}

然后你可以像这样使用它:

List<?> list1 = Arrays.asList(1, 2, 3);
List<?> list2 = Arrays.asList(1, 2, 3, "a");
System.out.println(checkElementType(list1, Integer.class)); // true
System.out.println(checkElementType(list2, Integer.class)); // false

【讨论】:

  • 感谢您提供的信息丰富的回答 :) ...我编辑了我的问题,请看一下...如果我弄错了,请告诉我
  • @TeFa:您更新后的问题的答案仍然是“不,那不可能。”
【解决方案2】:

任何告诉你这完全可能的人都是错误的。在运行时,无法判断空 Vector 是 Vector&lt;Integer&gt; 还是 Vector&lt;Rainbow&gt;

这或多或少是类型擦除的定义

【讨论】:

  • 所以你的意思是除非集合中至少有一个元素,否则不可能检查泛型类型?
  • 即使有元素,这个检查也不可靠。
【解决方案3】:

由于类型擦除,这是不可能的。

即使向量不为空,集合库也不能真正防止将不同类型的东西放入:

    Vector v = new Vector<Integer>();
    v.add("foo");
    System.out.println(v.get(0));

将无错误地运行并很好地打印不应该被允许的字符串值。

因此,任何在运行时确定泛型类型的尝试,即使是通过检查第一个元素的类型,都是不可靠的。

您可以在自己的通用代码中添加一个构造函数参数和一个保存该值的字段,以便您的代码确实在运行时知道类型。

这种策略很难应用于整个收藏库,但对于 Vector 来说,它的开始是:

public class TypedVector<E> extends Vector<E> {

    private Class<E> genericClass;

    public TypedVector(Class<E> clazz) {
        super();
        this.genericClass = clazz;
    }

    // many other constructors ... but probably not all of them

    public Class<?> getGenericClass() {
        return genericClass;
    }

    @Override
    public boolean add(E e) {
        if (!(genericClass.isAssignableFrom(e.getClass())))
                throw new IllegalArgumentException("Incorrect class");
        return super.add(e);
    }

    // many other overrides for run-time type safety
}

【讨论】:

    【解决方案4】:
    public boolean checkType(Vector<?> vec)
    {
      if(!vec.isEmpty())
      {
        if("String".equals(vec.get(0).getClass().getSimpleName()))
                 return false;
        else if("Integer".equals(vec.get(0).getClass().getSimpleName()))
                 return true;               
       }
    }
    

    希望这会有所帮助!

    【讨论】:

    • -1:这个问题非常明确地询问了 empty 向量,并包含清楚地表明 OP 知道如何为非空向量执行此操作的注释。
    猜你喜欢
    • 2017-12-24
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    • 1970-01-01
    • 2011-02-03
    相关资源
    最近更新 更多