【问题标题】:Is it possible to tie nested generics?是否可以绑定嵌套泛型?
【发布时间】:2010-04-06 08:36:15
【问题描述】:

是否可以将嵌套的泛型/捕获绑定在一起?

我经常遇到将类的映射查找到所述类的通用项的问题。具体来说,我想要这样的东西(不,T 没有在任何地方声明)。

private Map<Class<T>, ServiceLoader<T>> loaders = Maps.newHashMap();

简而言之,我希望 loaders.put/get 具有类似以下的语义:

<T> ServiceLoader<T> get(Class<T> klass) {...}
<T> void put(Class<T> klass, ServiceLoader<T> loader) {...}

以下是我能做到的最好的吗?我必须忍受不可避免的@SuppressWarnings("unchecked")吗?

private Map<Class<?>, ServiceLoader<?>> loaders = Maps.newHashMap();

【问题讨论】:

  • 你试过了吗?结果如何? (我自己之前没有尝试过这样的事情,但我很想知道它是否开箱即用?)
  • 很遗憾,它不起作用。我想知道是否有人想出了解决这个问题的方法。目前我正在使用双重捕获和@SuppressWarning。

标签: java generics capture


【解决方案1】:

让我看看我是否明白了你的意图:你想要一个存储 Class/ServiceLoader 对的地图,其中每对都由相同的 T 参数化,但 T 可能在不同对之间有所不同?

如果是这种情况,那么最好的解决方案是声明您自己的类,该类将展示这样的接口。在内部,它将这些对存储在一个通用的 Map&lt;Class&lt;?&gt;,ServiceLoader&lt;?&gt;&gt; 映射中。

public class MyMap {
   private Map<Class<?>, ServiceLoader<?>> loaders 
      = new HashMaps<Class<?>, ServiceLoader<?>>();

   public<T> void put(Class<T> key, ServiceLoader<T> value) {
      loaders.put(key, value);
   }

   @SuppressWarnings("unchecked")
   public<T> T get(Class<T> key) { return (ServiceLoader<T>) loaders.get(key); }
}

@SuppressWarnings("unchecked") 注释并不是纯粹的邪恶。您应该尽量避免它们,但在某些情况下,尽管编译器看不到,但您可以确定强制转换是正确的。

【讨论】:

  • +1,但 key.cast() 仅在值类型为 T 时才有效。 Josh Bloch 在“Effective Java”中将此称为“Typesafe Heterogeneous Container Pattern”。我通常在 put 方法中编写 loaders.put(key,key.cast(value)) ,然后如果用户以某种方式绕过编译时检查,则在添加值时仍会弹出错误,而不是在检索时弹出错误。
  • @Yardena - 你完全正确。我忽略了这一点。毕竟@SuppressWarnings 是无法避免的
【解决方案2】:

我的建议是为这种情况创建一个新对象。我看到你使用的是Maps.newHashMap(),所以我认为你使用的是 Google Guava,所以我将使用 ForwardingMap

public class Loader<T> extends ForwardingMap<Class<T>, ServiceLoader<T>> {

   private Map<Class<T>, ServiceLoader<T>> delegate = Maps.newHashMap();

}

一个简单的测试证明我的建议是有效的:

public class Loader<T> extends ForwardingMap<Class<T>, Class<T>> {

   private Map<Class<T>, Class<T>> delegate = Maps.newHashMap();

   @Override protected Map<Class<T>, Class<T>> delegate() {
      return delegate;
   }

   public static void main(String[] args) {
      Loader<Integer> l = new Loader<Integer>();

      l.put(Integer.class, Integer.class);

      // error
      l.put(Integer.class, String.class);
   }

}

【讨论】:

  • 我希望 T 在键/值对之间保持相同;不是整个系列。
猜你喜欢
  • 2016-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2011-09-15
  • 2012-09-30
相关资源
最近更新 更多