Map <key,list =“”set <objects =“”of =“”type =“”defined =“”by =“”key =“”>&gt;

时间:2015-05-20 10:01:11

标签: java generics dictionary

也许我在这里想错了,但是我想说我想要返回一堆不同类型的对象。例如很多人,个人资料,账户。我想把它们放在一个地图中,其中一个键就像Person.class,值将是一个Person实例列表。首先我想到了一个EnumMap,但是为什么我要为类列表创建一个ENUM,如果我能以某种方式自己使用这些类呢?

我试图用泛型来达到目标​​,但无法绕过定义。

这甚至可能吗?或者我在想一个糟糕的设计?

我可以提供不同的方法来检索部分结果。或者创建一个可以容纳它的类。但是如果我想在将来使用更多的类,Map会更灵活。

编辑:

我得到了一些答案,这似乎没有具体说明我在寻找什么,所以澄清:

我想要类似的东西:

{
 Person.class : [person1Instance, person2Instance,...], 
 Account.class : [account1Instance, account2Instance, account3Instance, ...], 
 Profile.class : [profile1Instance...]
}

我想避免施法。以某种方式使用密钥应该为项目列表定义类型(安全)的事实。

4 个答案:

答案 0 :(得分:3)

我已在TypedMaphttp://blog.pdark.de/2010/05/28/type-safe-object-map/

中实现了此功能

以下是一些演示代码:

TypedMap map = new TypedMap();

String expected = "Hallo";
map.set( KEY1, expected );
String value = map.get( KEY1 ); // Look Ma, no cast!
assertEquals( expected, value );

List<String> list = new ArrayList<String> ();
map.set( KEY2, list );
List<String> valueList = map.get( KEY2 ); // Even with generics
assertEquals( list, valueList );

魔法在关键:

final static TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
final static TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );

要解决您的问题,您需要为要在地图中保存的不同类型创建密钥:

TypedMapKey<List<Account>> ACCOUNTS = new TypedMapKey<List<Account>>(  "ACCOUNTS" );

然后你需要通常的get / create代码:

public <T> List<T> getList( TypedMapKey<List<T>> key ) {
    List<T> result = map.get(key);
    if(null == result) {
        result = new ArrayList<T>();
        map.put(key, result);
    }
    return result;
}

允许您使用以下方式访问列表:

List<Account> accounts = getList(ACCOUNTS);

答案 1 :(得分:1)

不允许使用不同类型的对象,因为在检索它们时我们遇到问题,我们不知道会出现什么类型的对象。

这是我的建议:

制作地图:

Map<Object, String> map = new HashMap<Object, String>();

让我们提出一些值:

Person p = new Person();

map.put(p, "Person");

Account a = new Account();

map.put(a, "Account");

假设您将传递不同的对象。

在检索这样的事情时:

for(Entry<Object, String> entry : map.entrySet()) {
  String choiceClassName = entry.getValue();

 switch(choiceClassName) {
   case "Person" : Person p = (Person) entry.getKey();
break;

case "Account" : Account a = (Account) entry.getKey();

break;


} 

}

答案 2 :(得分:0)

你不需要任何枚举。您可以使用instanceof来检查对象的类型。这就是我通常的做法,但我对其他人的其他答案感到好奇。

通常我只使用一个父类型和我的地图所需的通用方法(通常是一个接口)。 但有时我会使用这种方法,因为我真的不知道用户操作会将什么放入地图。

以此地图为例:

HashMap<String,Object> stuff = new HashMap<String,Object>();
stuff.add("joe",new Person());
stuff.add("new york", new City());

Iterator it = stuff.iterator();
while(it.hasNext()) {
   Object obj = it.next();
   if(obj instanceof Person) {
      Person p = (Person)obj;
   }
   if(obj instanceof City) {
      City c = (City)obj;
   }
}

答案 3 :(得分:0)

最后,我使用来自tobias_k comment的提示创建了我自己的TypedMultimap。

我创建了这个类:

import com.google.common.collect.ForwardingMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.Collection;

/**
 *
 * @author mimkorn
 */
public class TypedMultimap extends ForwardingMultimap<Class, Object> {

    private final HashMultimap<Class, Object> delegate;

    public TypedMultimap() {
        this.delegate = HashMultimap.create();
    }


   // IMPORTANT PART
    public <T> Collection<T> getSafely(Class<T> key) {
        return (Collection<T>) delegate().get(key);
    }

    public <T> boolean putSafely(
            Class<T> key, T value) {
        return delegate.put(key, value);
    }
   // TILL HERE    

   // CONVENIENCE
    public <T> boolean putSafely(T value) {
        return delegate.put(value.getClass(), value);
    }
   // TILL HERE

    @Override
    public Collection<Object> get(Class key) {
        return getSafely(key);
    }

    @Override
    public boolean put(Class key, Object value) {
        return putSafely(key, value);
    }

    @Override
    protected Multimap<Class, Object> delegate() {
        return delegate;
    }

}

编辑:现在你可以放(new SomeClass());它会将它放入映射中,在SomeClass.class下映射它。这样您只需添加数据而无需关心类,地图将为您排序。然后,您可以使用<T> Collection<T> getSafely(Class<T> key)

获取特定类型的所有实例

现在,当您调用getSafely或putSafely时,它会为您检查类型。缺点是,用户以某种方式需要知道,他应该使用单个参数put方法添加数据。此外,只有getSafely和putSafely,将检查编译时错误。

现在你可以这样做:

    TypedMultimap typedMultimap = new TypedMultimap();
    typedMultimap.putSafely(new ExportThing("prvý"));
    typedMultimap.putSafely(new ExportThing("druhý"));
    typedMultimap.putSafely(ExportThing.class, new ExportThing("prvý"));
    typedMultimap.putSafely(new ExportPhoneNumber("prvý"));
    typedMultimap.putSafely(ExportPhoneNumber.class, new ExportPhoneNumber("druhý"));
    Collection<ExportPhoneNumber> safely = typedMultimap.getSafely(ExportPhoneNumber.class);
    for (ExportPhoneNumber safely1 : safely) {
        System.out.println(safely1.getPhoneNumber());
    }

将返回:

druhý
prvý

尝试做

typedMultimap.putSafely(ExportThing.class, new ExportPhoneNumber("prvý")); 

将导致编译时错误。

这是一个有点Map&gt;。如果您需要地图&gt;例如,用作代理ArrayListMultimap而不是HashMultimap