想象一下你有类似这样的情况:
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作为我的地图的值类型,但我希望能够访问我的特定方法。我已经做了一些研究,试图在我得到它们时动态投射我的物体,但我没有找到任何令人满意的东西。 提前致谢
答案 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,您无法自动执行此操作。 Map
和List
不知道他们存储的是什么类型,所以他们无法在这里提供帮助。他们正在存储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