java - 从 T 到 T 的 map

标签 java scala generics

假设您想使用 Map并且您有以下要求:您希望每个键映射到相同类型的值。

Map<???> map = ...;
map.put(42, 15);
map.put("hello world", 15); // compile time error, because you cannot map from string to int.
map.put("hello world", "foobar");
map.put(new Foo(), new Foo());
Integer i = map.get(42);
String s = map.get("hello world");
Foo f = map.get(new Foo());

当然,上面的代码不会编译,但诀窍是你从 T 映射。至T哪里T未在实例化时定义。映射仅返回与参数相同的类型。当然它可以变得更有趣,比如从T映射至List<T> 。这没有丑陋的选角吗?

Scala 的类型系统通常被认为比较先进,Scala 有解决方案吗?

如果上述两个问题的答案都是“否”,那么是否有任何语言支持这种类型?

注意: 上面代码中的 Map 只是采用两个泛型参数的类型的示例。我对 Map 并不特别感兴趣,但对类型系统更感兴趣。

最佳答案

这并不完全是您所描述的,但 Java 中的一个众所周知的模式是类型安全异构容器 ( Effective Java Item 29 ),它映射 Class<T>T 的实例。 Guava提供 ClassToInstanceMap 实现此模式的接口(interface)。


在 Java 中,您可以临时调整您所描述的类型,但它不会很漂亮。

public class TTMap extends ForwardingMap<Object, Object> {
  private final HashMap<Object, Object> delegate = new HashMap<>();
  @Override
  protected Map<Object, Object> delegate() {
    return delegate();
  }

  @SuppressWarnings("unchecked")
  public <T> T getType(T key) {
    return (T)delegate().get(key);
  }

  @SuppressWarnings("unchecked")
  public <T> T putType(T key, T value) {
    return (T)delegate().put(key, value);
  }

  @Override @Deprecated
  public Object put(Object key, Object value) {
    Preconditions.checkState(key == value || value.getClass().equals(key.getClass()));
    return delegate.put(key, value);
  }

  @Override @Deprecated
  public void putAll(Map<? extends Object, ? extends Object> map) {
    standardPutAll(map);
  }
}

这使用 ForwardingMap 给你一个Map<Object, Object>但由于运行时约束,键和值将始终具有相同的类型。您需要使用getType()putType()避免运行时错误的风险; put()putAll()只能在运行时异常的情况下强制执行此约束。您还可以添加 putAll(TTMap)方法,如果你愿意的话。

key == value签到put()允许null只要 key 都满足和value为空。如果只有其中之一,您将得到 NullPointerException在类平等检查中。

另请注意@Radiodef 的评论 - 每个类型都会扩展 Object ,因此使用泛型无法阻止两种类型被强制转换为 Object并插入。您需要额外的运行时检查来解决这个问题。

如果实现Map不是必需的,您可以相当轻松地在新类上遵循类似的模式(私有(private) Map<Object, Object> 和类型化的 getter 和 setter)。

关于java - 从 T 到 T 的 map ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30943271/

相关文章:

java - 从 TextInputDialog 将 Optional<String> 转换为 Integer 时出错

Scala - 最终超时和 Thread.sleep() 之间的区别

generics - 如果我已经为 U 实现了 From<T>,Rust 是否为 Vec<U> 实现了 From<Vec<T>>?

c# - 从通用基类获取实现的类型

Java 包包含其他文件中的方法

java - 等待对象在 CORBA 命名服务中绑定(bind)

java - Gson Java 保留关键字

scala - Spark 斯卡拉 : JniBasedUnixGroupsMapping: Error getting groups for XXX: The user name could not be found

scala - 如何定义接受带有参数的函数的延迟(按名称)参数?

Java 类型不匹配,无法转换为将自身作为泛型类型返回