Java:当项目不相关时,绑定异构集合

时间:2010-11-14 04:06:55

标签: java generics collections

如果我有异构集合,我确切知道我将要放置的类型是否有办法强制执行此操作。

例如,假设我有一个具有String键和值的映射,该映射可以是三个不相关的类型。现在我知道我只会放ClassA和ClassB或java.lang.String

例如这里是代码

public HetroCollection
{
    public Map<String,Object> values;
}

public ClassA
{
}

public ClassB
{
}

public static void Main(String args[])
{
   HetroCollection collection = new HetroCollection();
   collection.values.add("first", new ClassA());
   collections.values.add("second", new ClassB());
   collections.values.add("third" , "someString");
   //BAD want to stop random adds
   collections.values.("fourth" , new SomeRandomClass());
}

我想到的选项是:

  • 让类实现一个通用接口并在Map上使用Generics(问题是,如果这也涉及JDK或第三方的库类,那么更改类不是一个选项

  • 隐藏地图并提供像

    这样的方法

    put(String key,ClassA value); put(String key,ClassB value); put(String key,String value); get(String key);

  • 重新思考设计而不是使用异构集合(不确定我将如何以其他方式表示)

寻找最佳实践答案。

5 个答案:

答案 0 :(得分:2)

我认为“最佳实践”解决方案是您的第一和第三选择,只要情况允许。

你没有考虑的另一个选择是这样的:

public class MyMap extends HashMap<String, Object> {
    ...
    // constructors
    ...
    @Override
    public void put(String key, Object value) {
        if (value instanceof ClassA || value instanceof ClassB) {
            super.put(key, value);
        } else {
            throw new IllegalArgumentException("Verbotten!");
        }
    }
    ...
}

您可以将其与第二个选项结合使用,以便存在静态类型选项,甚至可能将put(String, Object)方法标记为已弃用以阻止其使用。

最后,可以选择忽略问题,并依赖应用程序员不要将随机内容放入地图中。根据具体情况,这甚至可能是最佳解决方案。

答案 1 :(得分:1)

嗯,你已经证明你首先想到的不是一个选择。如果你真的需要这个功能,第二个想法是最好的选择。否则最好的选择是重新考虑你的方法。但是,如果我们知道一点上下文,它会更容易帮助。

答案 2 :(得分:0)

这个被称为类的Java有一个很好的工具。举个例子,你可以这样写一个:

public class Foo {
  private ClassA first;
  private ClassB second;
  private String someString;

  ...

  public void setFirst(ClassA first) {
    this.first = first;
  }

  public ClassA getFirst() {
    return first;
  }

  ...
}

说真的,鉴于你所说的这听起来就像你想要的那样。如果您只想允许特定键,其值可能只​​是特定类型(取决于键本身)......那就是class。如果有一些非常强烈的理由让你需要在这里使用String地图密钥(这对我来说似乎不太可能),请解释一下。

修改

当我回答这个问题时,由于某种原因,我需要强制执行仅映射到特定类型值的特定键。再看一遍,似乎情况可能并非如此。如果情况并非如此,我认为您最好的选择是重新考虑设计(举例说明您需要这样做的原因可能会有所帮助)。如果你这样做并且没有想出任何东西,我认为#2是最好的选择。它以某种类型安全的方式强制限制地图可以具有的值类型。

答案 3 :(得分:0)

还有第四种选择:

如果你想将这些类型的实例粘贴到一个集合中,很可能它们有一些共同之处。如果你不能引入一个通用的超类型来表达这种共性,你仍然可以引入一个具有这种公共超类的并行类层次结构,并声明你的地图可以保存那种类型的项目。

// You can find a better name ;-)
abstract class Foo {
    public abstract void foo();

    public void bar() {
        // something generic
    }

    public abstract void visit(FooVisitor visitor);
}

class ClassAFoo {
    final ClassA delegate;

    // Constructor and implementations for foo()

}

class ClassBFoo {
    final ClassB delegate;

    // Constructor and implementations for foo()

}

class StringFoo {
    final String delegate;

    // Constructor and implementations for foo()
}

优点:

  1. 静态类型安全
  2. 您可以将方法添加到公共类型或实现访问者模式以打开包装值的类型
  3. 编译器可以在使用地图时检查您是否已经处理了所有类型(与使用一系列if语句来打开类型相反)
  4. 缺点:

    1. 样板代码,复杂性

答案 4 :(得分:0)

理论上,使用Functional Java中的HList可以实现List中混合对象的类型安全性。请参阅blog postExamples。来自IBM developerworks的相关this article也是如此。我在理论上写道,因为在实践中,类型声明只能处理有限数量的元素,并且它会迅速增长。