我们再次使用参数化的Class作为类型信息的钩子,调整后的Context将使用参数化的Key而不是Class。
  public class Context {
  private final Map<Key<?>, Object> values = new HashMap<>();
  public <T> void put( Key<T> key, T value ) {
  values.put( key, value );
  }
  public <T> T get( Key<T> key ) {
  return key.type.cast( values.get( key ) );
  }
  [...]
  }
  客户端将这样使用这个版本的Context:
  Context context = new Context();
  Runnable runnable1 = ...
  Key<Runnable> key1 = new Key<>( "id1", Runnable.class );
  context.put( key1, runnable1 );
  Runnable runnable2 = ...
  Key<Runnable> key2 = new Key<>( "id2", Runnable.class );
  context.put( key2, runnable2 );
  // several computation cycles later...
  Runnable actual = context.get( key1 );
  assertThat( actual ).isSameAs( runnable1 );
  虽然这个代码片段可用,但仍有缺陷。在Context#get中,Key被用作查询参数。用相同的identifier和class初始化两个不同的Key的实例,一个用于put,另一个用于get,后get操作将返回null 。这不是我们想要的……
  //译者附代码片段
  Context context = new Context();
  Runnable runnable1 = ...
  Key<Runnable> key1 = new Key<>( "same-id", Runnable.class );
  Key<Runnable> key2 = new Key<>( "same-id", Runnable.class );
  context.put( key1, runnable1 );//一个用于put
  context.get(key2); //另一个用于get --> return null;
  幸运的是,为Key设计合适的equals 和hashCode 可以轻松解决这个问题,进而使HashMap 查找按预期工作。后,你可以为创建key提供一个工厂方法以简化其创建过程(与static import一起使用时有用):
  public static  Key key( String identifier, Class type ) {
  return new Key( identifier, type );
  }
  结论
  “集合API说明了泛型的一般用法,限制你每个容器只能有固定数目的类型参数。你可以通过将类型参数放在键上而不是容器上来避开这个限制。对于这种类型安全的 异构容器,可以用Class对应作为键。”(Joshua Bloch,《Effective Java》第29项)。
  给出上述闭幕词,也没有什么要补充的了,除了祝愿你成功混合苹果和梨……