【问题标题】:java.util.Map with various generic class objectsjava.util.Map 与各种通用类对象
【发布时间】:2014-08-31 17:58:28
【问题描述】:

我喜欢有一个 java.util.Map,它包含不同的通用类对象。在我的情况下,这样的处理程序:

public interface Handler<s>{
 public void encode (S data, OutputStream out);
 public S decode (InputStream in, long length);
}

我有实现类,例如:

public class SpecializedHandler implements Handler<FirstSpecialItem>{
 public void encode (SpecialItem data, OutputStream out){
  // do something
 }
 public SpecialItem decode(InputStream in, long length){
  // do something
 }
}

和另一个实现 Handler 的类。

对于 FirstSpecialItem 和 SecondSpecialItem 存在一个父类 AbstractSpecialItem

因为我已经在使用encode和decode时遇到了很多问题,所以我最终得到了以下地图,它可以使用decode和encode如下:

Map<Long, Handler<? super AbstractSpecialItem>> handlers;
// I can use it as follows
AbstractSpecialItem item = new FirstSpecializedItem();

handlers.get(1L).encode(item,System.out);   
AbstractSpecialItem returnVal = handlers.get(1L).decode(System.in, 100L);

但是,我无法通过添加不同的 Handler 实现来创建地图,例如:

SpecializedHandler a = new SpecializedHandler();
SpecializedSecondHandler b = new SpecializedSecondHandler();
Map<Long, Handler<? super AbstractSpecialItem>> handlers = new HashMap<Long,Handler<? super AbstractSpecialItem>>();
handlers.put(0L, a); // does not work
handlers.put(1L, b); // does not work 

Eclipse 总是说这些值不适用于地图。 我认为这种行为是有效的,并试图更好地理解泛型和 PECS 原理(通过网络和一些书籍查看)。但我还是不明白,想办法解决。我有带有特殊泛型类型的处理程序类,并且能够使用方法(编码、解码)以及创建处理程序映射。

【问题讨论】:

  • 试试Map&lt;Long, Handler&lt;? extends AbstractSpecialItem&gt;&gt;

标签: java generics hashmap


【解决方案1】:

如果您使用Map&lt;Long, Handler&lt;? extends AbstractSpecialItem&gt;&gt; 而不是Map&lt;Long, Handler&lt;? super AbstractSpecialItem&gt;&gt;,它应该可以工作。注意 extends 而不是 super,为了更详细的解释,我建议你查看这个问题的答案:java generics super vs. extends

这是一个工作示例:

import java.io.*;
import java.util.*;

public class Test {
  public abstract class A<T extends Closeable> { }
  public class B<T extends Closeable> extends A<T> { }
  public class C<T extends Closeable> extends A<T> { }

  public Map<String, A<? extends Closeable>> map = new HashMap<>();
  // instance initializer
  {
    map.put("1", new B<InputStream>());
    map.put("2", new C<Reader>());
  }
}

【讨论】:

    【解决方案2】:

    在你的情况下,你应该使用

    Map<Long, Handler<? extends AbstractSpecialItem>> handlers = new HashMap<Long, Main.Handler<? extends AbstractSpecialItem>>();
    

    您可以在此处了解 super 和 extends 之间的区别:Difference between <? super T> and <? extends T> in Java

    【讨论】:

    • @Lolo 和 Nemo,感谢您的快速重播。是的,这是正确的,但据我尝试过,如果我使用扩展,我将无法再使用编码方法。 Eclipse显示如下失败,如果我尝试调用它,如下:handlers.get(1L).encode(item,System.out);handlers.get(1L).encode((AbstractSpecialItem)item,System.out);
    • @Lolo 和 Nemo,感谢您的快速回复。是的,但是如果我使用extends,我就不能使用encode-Methode。如果调用 Eclipse 会显示以下故障:handlers.get(1L).encode(item,System.out);handlers.get(1L).encode((AbstractSpecialItem)item,System.out);_Error: Handler 不适用于参数(AbstractSpecialItem,PrintStream)。 FirstSpecializedItem。编码中的项目似乎是 null 类型。
    • 我不确定我是否了解您的用例。让我问你一下;作为开发人员,您需要传递编码参数。当你从地图中得到一个处理程序时,你怎么知道处理程序的类型?您需要知道调用 encode 方法的类型(使用 FirstSpecialItem 或 SecondSpecialItem)。
    • 我知道我用作地图中处理程序索引的键的类型(不是我的想法)。然而,关键不是类型的类对象,它只是该类型的一个众所周知的索引。目前,我发现我的解决方案使用原始类型和读取器和写入器类,而不是同时使用两者的序列化器类。现在我对泛型 PECS 原则的问题更少了,我想到,这在单一责任原则方面更好。
    • 然而这不是我第一个问题的答案,它是一种解决方法。
    猜你喜欢
    • 2013-09-03
    • 2012-10-19
    • 1970-01-01
    • 2011-06-17
    • 2011-11-16
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多