【问题标题】:Java collections -- polymorphic access to elementsJava 集合——对元素的多态访问
【发布时间】:2013-11-13 05:44:50
【问题描述】:

我有一个 LinkedHashSetThisType 值。 ThisType 正在实现接口 ThatType

我需要这个集合的多态使用——能够将它指向为 LinkedHashSet。

这是怎么做到的?

我知道这是一个幼稚的问题,但我尝试过的几件事没有奏效,我想以正确的方式去做。

提前致谢。

//================================

更新:更多细节:

在下面的代码中,ThisType 实现了 ThatType-- ThatType 是一个接口。

//LinkedHashMap<Integer, ? extends ThatType> theMap = new LinkedHashMap<>();
LinkedHashMap<Integer, ThisType> theMap = new LinkedHashMap<>();
for (Integer key:intArray)  {
    ThisType a = new ThisType();
    if (theMap.containsKey(key))  {
        a = theMap.get(key);    
        a.doStuff();
    } else {
        a.doOtherStuff();
    }
    theMap.put(key, a);
}

最后,我想将 theMap 作为 ThatType ** 的集合返回,而不是 **ThisType

这就是链条断裂的地方。使用注释行(第一行)进行声明会导致散列的 put()get() 方法出现类型不匹配错误。

不确定这是否重要——但是, 我将结果返回为 LinkedHashSet。我正在进行从 LinkedHashMapLinkedHashSet 的转换。但是,对于映射或集合中的集合值的多态引用,没有任何效果。到目前为止,我在所有这些操作中使用的所有且唯一的类型是 ThisTypeThatType 几乎在我尝试过的任何地方都给了我一些错误。

【问题讨论】:

  • 你到底需要做什么?
  • 我会把它作为参数传递
  • 我读了三次,仍然无法理解您想要达到的目标。
  • 你能详细说明“多态使用”吗?
  • 或者更确切地说,将它作为 LinkedHashSet 返回,而里面到处都是 LinkedHashSet

标签: java collections polymorphism


【解决方案1】:

我认为你想要的是使用通配符。

 LinkedHashSet<? extends ThatType> someFunction(LinkedHashSet<? extends ThatType> set) {
      return set;
 }

正如在别处解释的那样,LinkedHashSet&lt;ThisType&gt; 不是LinkedHashSet&lt;ThatType&gt; 的子类,因为LinkedHashSet&lt;ThisType&gt; 不能接受ThatType 对象。

LinkedHashSet&lt;? extends ThatType&gt; 中的通配符表示扩展 ThatType 的某个类的 LinkedHastSet(不确定是什么)。

虽然你可能想考虑使用这个:

 Set<? extends ThatType> someFunction(Set<? extends ThatType> set) {
      return set;
 }

【讨论】:

  • 反之亦然——Q 表述错误。但我会试试这个。
  • 我想保留元素的顺序——必须是链表
【解决方案2】:

当你声明一个通配符有界类型参数时

LinkedHashMap<Integer, ? extends ThatType> theMap = new LinkedHashMap<>();

您是在告诉编译器类型参数可以是任何属于ThatType 子类型的类。想象一下这种情况

LinkedHashMap<Integer, ? extends ThatType> theMap = getLinkedHashMap();

getLinkedHashMap() 定义为

public LinkedHashMap<Integer, OtherType /* which implements ThatType */> getLinkedHashMap();

之前的分配会起作用,因为OtherTypeThatType 的子类型。然而,你不能期待

ThisType a = theMap.get(key);

工作。由于通配符,您所知道的是地图肯定包含ThatType 实例(称为上限),但它们可能是OtherTypeThatType 类型(或其他子类型ThatType)。最多你可以做

ThisType a = (ThisType) theMap.get(key);

投射返回值,但随后您将自己开放给ClassCastException

同样,您不能使用除null 之外的任何其他内容调用put()

theMap.put(someInt, null); // will compile
theMap.put(someInt, new ThisType()); // will not compile
theMap.put(someInt, new OtherType()); // will not compile

编译器不允许你添加任何东西,因为它不能保证地图包含什么,同样是因为通配符绑定。但是null can be used because

空引用总是可以进行加宽引用转换 到任何引用类型。

所以null 是一个有效参数,因为它是the lower bound of the wildcard


您处于一种特殊情况,您的方法似乎在内部创建了LinkedHashMap,并且您知道将传递给它的内容。因此,您可以执行以下操作

public static LinkedHashMap<Integer, ThatType> getTheSet(int[] intArray) {
    LinkedHashMap<Integer, ThatType> theMap = new LinkedHashMap<>();

    for (Integer key : intArray) {
        ThisType a = new ThisType();
        if (theMap.containsKey(key)) {
            a = (ThisType) theMap.get(key); // cast it because you know they will definitely be `ThisType` references
            a.doStuff();
        } else {
            a.doOtherStuff();
        }
        theMap.put(key, a);
    }

    return theMap;
}

由于ThisTypeThatType 的子类型,您可以将ThisType 的实例放入映射中。您需要注意如何使用此方法的返回值。编译器只知道返回值包含ThatType 引用。它不知道他们实际上是ThisType

【讨论】:

    【解决方案3】:

    您需要Set&lt;? super ThisType&gt; 的通配符。看下面的例子

    public static void main(String[] args) {
        Set<ThatType> set=new LinkedHashSet<>();
        Set<ThisType> set2=new LinkedHashSet<>();
    
        someFunction(set);
        someFunction(set2);
    }
    
    static void someFunction(Set<? super ThisType> set) {
    
    }
    
    class ThisType implements ThatType{
    
    }
    interface ThatType{
    
    }
    

    【讨论】:

      猜你喜欢
      • 2014-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-25
      • 2011-01-02
      • 2012-01-26
      • 1970-01-01
      相关资源
      最近更新 更多