【问题标题】:Type-safe varargs method that initialises a Map初始化 Map 的类型安全可变参数方法
【发布时间】:2008-11-28 11:11:02
【问题描述】:

我想编写一个可以用来初始化 Map 的方法。第一剪:

Map map(Object ... o) {for (int i = 0; i < o.length; i+=2){result.put(o[i], o[i+1])}}

简单,但不是类型安全的。使用泛型,可能类似于:

<TKey, TValue> HashMap<TKey, TValue> map(TKey ... keys, TValue ... values) 

但不支持该语法。所以最终我得出了这个结论:

public static <TKey, TValue, TMap extends Map<? super TKey, ? super TValue>> TMap map(TMap map, Pair<? extends TKey, ? extends TValue> ... pairs) {
    for (Pair<? extends TKey, ? extends TValue> pair: pairs) {
        map.put(pair.getKey(), pair.getValue());
    }
    return map;
}

public static <TKey, TValue> HashMap<? super TKey, ? super TValue> map(Pair<? extends TKey, ? extends TValue> ... pairs) {
    return map(new HashMap<TKey, TValue>(), pairs);
}

public static <TKey, TValue> Pair<TKey, TValue> pair(TKey key, TValue value) {
    return new Pair<TKey, TValue>(key, value);
}

public static final class Pair<TKey, TValue> {
    private final TKey key;
    private final TValue value;
    Pair(TKey key, TValue value) {this.key = key; this.value = value; }
    public TKey getKey() {return key;}
    public TValue getValue() {return value;}
}

但是当我尝试它时,我需要投射它:

private static final Map<? extends Class<? extends Serializable>, ? super TypeHandler<? extends Serializable > > validCodeTypes =
    /* (Map<? extends Class<? extends Serializable>, ? super TypeHandler<? extends Serializable >>) */
 map(
    pair(Integer.class,   new IntHandler()),
    pair(Integer.TYPE,    new IntHandler()),
    pair(Character.class, new CharHandler()),
    pair(Character.TYPE,  new CharHandler()),
    pair(String.class,    new StringHandler())
);

private interface TypeHandler<TType extends Serializable> {}

private static class CharHandler implements TypeHandler<Character> {}
private static class IntHandler implements TypeHandler<Integer> {}
private static class StringHandler implements TypeHandler<String> {}

谁能告诉我如何编写我的 map() 方法,使其完全通用但不需要强制转换?

【问题讨论】:

    标签: java generics variadic-functions


    【解决方案1】:

    为了让自己的生活更轻松,切勿使用包含通配符的返回类型。通配符类型通常仅用于方法参数。

    那么,试试这个:

    public static <TKey, TValue, TMap extends Map<TKey, TValue>> TMap map(TMap map, Pair<? extends TKey, ? extends TValue>... pairs) {
        for (Pair<? extends TKey, ? extends TValue> pair: pairs) {
            map.put(pair.getKey(), pair.getValue());
        }
        return map;
    }
    
    public static <TKey, TValue> HashMap<TKey, TValue> map(Pair<? extends TKey, ? extends TValue>... pairs) {
        return map(new HashMap<TKey, TValue>(), pairs);
    }
    

    我还没有测试过,但试一试,看看你的表现如何。

    P.S.,而不是使用虚构的 Pair 类型,您可能会发现使用 Map.Entry 更容易。

    【讨论】:

      【解决方案2】:

      为什么不这样?我是不是误会了什么?

      import java.util.HashMap;
      import java.util.Map;
      
      public class ToHash {
          public static <K, V> Map<K, V> toHash(Object... objects) {
              Map<K, V> map = new HashMap<K, V>(objects.length / 2);
              if (objects.length % 2 != 0) {
                  throw new IllegalArgumentException("Odd number of elements: " + objects.length);
              }
              for (int i = 0; i < objects.length; i += 2) {
                  map.put((K) objects[i], (V) objects[i + 1]);
              }
              return map;
          }
      }
      

      【讨论】:

      • 没有警告:pastebin.com/f2d59bc93 产生结果:1=一个 2=两个 3=三个
      • 它“有效”,但您失去了编译时类型安全性。显然,OP 竭尽全力使他们的代码在编译时类型安全。
      • 是的,但这太糟糕了。他不会通过使用可变参数来得到它,除非键和值是相同的类型。
      【解决方案3】:

      pgdx:你的技术确实有效,但它并不妨碍我说这样的话:

      Map<Long, Date> map = toHash("hello", "world");
      

      我一直在寻找一种方法,让编译器能够发现任何类型不匹配的错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-25
        • 2014-02-04
        • 2019-08-02
        • 1970-01-01
        • 1970-01-01
        • 2017-02-23
        • 1970-01-01
        • 2017-01-07
        相关资源
        最近更新 更多