HashMap具有不同的可能值类型

时间:2017-05-01 21:35:14

标签: java

想象一下你有类似这样的情况:

class AbstractClass{void sharedMethod()}
class ClassOne extends AbstractClass{void sharedMethod(); void specificMethod()}
class ClassTwo extends AbstractClass{void sharedMethod(); void specificMethod2()}

我想存储在这样的地图中:

HashMap<String, List<SOMETHING_I_DON'T_KNOW_IN_ADVANCE>> hm = new HashMap<>();
hm.put("blabla", List<ClassOne>);
hm.put("blublu", List<ClassTwo>);

我知道我可以将AbstractClass作为我的地图的值类型,但我希望能够访问我的特定方法。我已经做了一些研究,试图在我得到它们时动态投射我的物体,但我没有找到任何令人满意的东西。 提前致谢

4 个答案:

答案 0 :(得分:2)

将创建&#34; abstract void specificMethod()&#34;在你的AbstractClass中,然后在你的具体类中使用specificMethod()的具体版本为你工作?

这样你就不用担心是否要调用specificMethodOne()或specificMethodTwo()...... AbstractClass对象已经知道它应该使用哪个版本的specificMethod()。

答案 1 :(得分:2)

  

我知道我可以将AbstractClass作为我的地图的值类型,但我希望能够访问我的特定方法。

我假设您要这样做:

List<ClassOne> one = hm.get("blabla");
one.specificMethod();
// or
List<ClassTwo> two = hm.get("blublu");
two.specificMethod2();

很遗憾,由于type erasure,您无法自动执行此操作。 MapList不知道他们存储的是什么类型,所以他们无法在这里提供帮助。他们正在存储Object s。

Collection中存储不同类型的对象是一种难以正确支持的模式,并且一旦从Map中获取值,您就需要自己进行投射。

List<AbstractClass> list = hm.get("blabla");
if (list instanceof ClassOne) {
    ClassOne one = (ClassOne)list;
    one.specificMethod();
} else if (list instanceof ClassTwo) {
    ClassTwo two = (ClassTwo)list;
    two.specificMethod2();
}
...

是的,这是严重且容易出错的,但使用Java泛型并没有简单的方法。

答案 2 :(得分:1)

我会考虑将数据封装在类中,例如

private static class MyMessages
{
    final List<ClassOne> typeOneMessages = new ArrayList<>();
    final List<ClassTwo> typeTwoMessages = new ArrayList<>();

    public void addTypeOne(ClassOne c) {
        typeOneMessages.add(e);
    }

    // add appropriate getter methods; or a stream
    public Stream<ClassOne> streamOne()
    {
        return typeOneMessages.stream();
    }

    // same for type two
}

或者按照Rick Stabile的建议,并在抽象类中定义一个方法。

如果您希望将它们保持在一起,则必须进行检索,例如:

public static void main(String[] args)
{
    final Map<String, List<? extends AbstractClass>> map = new HashMap<>();

    List<ClassOne> ones = new ArrayList<>();
    for (int i = 0; i < 4; i++) {
        ones.add(new ClassOne());
    }

    List<ClassTwo> twos = new ArrayList<>();
    for (int i = 0; i < 8; i++) {
        twos.add(new ClassTwo());
    }

    map.put("ones", ones);
    map.put("twos", twos);

    List<? extends AbstractClass> out = map.get("ones");
    // can call shared method on the contents
    out.stream().forEach(a -> a.sharedMethod());

    // will have to cast to the specific type
    out.stream().filter(a -> a instanceof ClassOne)
        .forEach(c1 -> ((ClassOne)c1).specificMethod());

    List<? extends AbstractClass> out2 = map.get("twos");
    // can call shared method on the contents
    out2.stream().forEach(a -> a.sharedMethod());

    // will have to cast to the specific type 2
    out2.stream().filter(a -> a instanceof ClassTwo)
        .forEach(c2 -> ((ClassTwo)c2).specificMethod2());        
}

答案 3 :(得分:0)

你可以通过使用&#34;通配符(?)参数&#34;来实现这一点。并且由于&#34; Type Safety&#34;机制演员阵容是不可避免的。 这对我有用:

    HashMap<String, List<? extends AbstractClass>> hm = new HashMap<>();
    ClassOne class1 = new ClassOne();
    ClassTwo class2 = new ClassTwo();

    List<ClassOne> c1l = new ArrayList<>();
    c1l.add(class1);
    List<ClassTwo> c2l = new ArrayList<>();
    c2l.add(class2);



    hm.put("blabla", c1l);
    hm.put("blublu", c2l);

    @SuppressWarnings("unchecked")
    List<ClassOne> xyy = (List<ClassOne>)hm.get("blabla");
    ClassOne c1 = xyy.get(0);
    c1.specificMethod1();

我的输出是:

Hello! from SpecificMethod1