Java:用于保存不同类型的基元的通用集合

时间:2014-12-11 12:04:47

标签: java generics collections

这可能是一个愚蠢的问题,但Java中是否有一种类型的集合可以保存不同类型的原语?我目前正在创建一种格式化两种类型对象的方法,并且我试图将参数存储在数组中,以避免使用带有十个+参数的方法,而是使用两个数组来保存值并传递相反,他们。

这些类型将是字符串,整数和布尔值的组合。

3 个答案:

答案 0 :(得分:4)

Java中的基元可以装入对象中。类型Object可以保存Stringintboolean类型的值,方法是将原始int值存储为Integer个对象和原语boolean值为Boolean个对象。这通常可以在没有程序员明确地包装或展开它们的情况下进行,这称为自动装箱。

因此,任何包含Object类型值的集合或数组,例如Object[]List<Object>等,都可以保存您的值。

例如:

Object[] array = new Object[] { 1, 2, true, "hi" };

List<Object> list = new ArrayList<Object>();
list.add(5);
list.add(false);
list.add("test");

对于方法的变量参数,只需使用Object...

void myMethod(Object... params) {
  // ...
}

处理数组或Object值集合时,可以使用instanceof和强制转换来查找类型并正确处理它们。

警告

当自动装箱以输入Object时,基元会直接装入Object值。在以下代码中:

short shortValue = 0;
int myPrimitive = shortValue;
Object myObject = shortValue;

myPrimitive的类型为int,但myObject的类型为Short。你问了一个Object,你有一个!请注意您对Object类型对象的假设,因为原则上您不能假设Object以外的其他任何内容。

幸运的是,您不必总是为每个原始数字类型检查Object。在大多数情况下,它足以将其强制转换为Number,然后使用例如.intValue()来获取int类型的值。也就是说,代码如下:

double x = 2.3;
Object o = x;
int i = ((Number) o).intValue();

相当于:

double x = 2.3;
int i = (int) x;

答案 1 :(得分:2)

可以在Java中保存整数的唯一“集合”是一个数组,它只能保存单个类型的基元。

如果需要收集多种类型的基元,可以创建一个具有多个基本成员的类,然后使用任何要存储该类的多个实例的Collection。

答案 2 :(得分:2)

假设你真的需要这样一个集合,你想要避免拳击价值的成本,你可以通过小心支持已经实现的原始集合such as Trove自己实现这样的集合。由于您没有指定所需的集合类型,让我们看一下将原始整数映射到您命名的值的示例映射:

class PrimitiveMap {

  final TIntBooleanMap booleans;
  final TIntIntMap ints;
  final TIntObjectMap<String> strings;

  // Constructor omitted

  void putBoolean(int index, boolean value) {
    removeIndex(index);
    booleans.put(index, value);
  }

  boolean getBoolean(int index) {
    booleans.get(index);
  }

  // similarly for the other collection types

  private removeIndex(int index) {
    booleans.remove(index);
    ints.remove(index);
    strings.remove(index);
  }
}

明显的缺点是你需要记住插入的元素的类型。或者,您可以在访问集合时使用盒装值,然后在存储值之前解析该框:

public void put(Object value) {
  if(value instanceof Boolean) {
    putBoolean((Boolean) value);
  } else if(value instanceof Integer) {
    putInteger((Integer) value);
  } else if(value instanceof String) {
    putString((String) value);
  }
  throw new IllegalArgumentException("Illegal value = " + value);
} 

public Object get(int index) {
  boolean booleanValue = booleans.get(index);
  if(booleanValue != booleans.getNoEntryValue()) {
    return booleanValue;
  }
  int intValue = ints.get(index);
  if(intValue != ints.getNoEntryValue()) {
    return intValue;
  }
  String stringValue = strings.get(index);
  if(stringValue != null) {
    return stringValue;
  }
  return null;
} 

请注意,如果您真的想要优化内存占用,这种方法可以获得回报,因为您可以避免保留对装箱对象的引用的开销。我假设您需要维护大量的集合才能衡量差异。在实施此类集合之前,请务必检查您的应用程序的足迹。

此方法对于列表的工作方式类似,其中实现也将由每个基元类型的映射支持,只有访问API不同。对于集合,您可以执行类似的操作,即用TXXXSet备份每个基元集合。