3

好的,这就是场景。我有总是在一起的静态键对。一个键是索引(aka ),一个键是描述(aka or )。我事先知道所有这些键,所以唯一真正改变的是值,永远不会添加新键。intstringenum

然而,这些值可以是任何类型:string、int、long。有些值不是单数,而是由多个值组成。但是,我事先确实知道每个密钥对将指向哪种类型的值。

这些值很可能总是使用索引来设置。但是,我希望能够通过索引(int)或描述(字符串/枚举)快速访问值不要循环,希望也不要强制转换)。此外,通过索引访问值时,我还应该可以访问描述

这可能会使事情更清楚:

1/Name ----> "danny"        //1 and Name are known in advance and always go together. also, they always point to a string
2/Age  ----> 24             //2 and Age are known in advance and always go together. also, they always point to an int
3/Time ----> 352343463463L  //3 and Time are known in advance and always go together. also, they always point to a long
4/Occupation    ---> [description] "magician"
                ---> [type] "entertainer"
                ---> [years] 3              //4 and Status are known in advance and always go together. also they will always point to 2 strings and and an int (or an object contraining 2 strings and an int...)

所需功能:

set(1, "Jasmine");
get(1);             //returns "Jasmine"
get(Name);          //return "Jasmine"  (name can be either string or enum I suppose)
getDescription(1);  // returns Name (again, name could be either string or enum). this function could possibly be merged with get(1) to have it return both description and value in the first place.

set(2, 32);
get(2);             //returns 32
get(Age);            //returns 32
4

4 回答 4

2

创造

class Entry {
  int index;
  String description;
  Object value;
}

声明 2 个 HashMap:

HashMap<Integer, Entry> idxValue=new HashMap<Integer, Entry>();
HashMap<String, Entry> descrValue=new HashMap<String, Entry>();

定义方法来存储和检索适用于两个表的条​​目和值。

于 2013-10-09T08:02:34.227 回答
1

您可以为此使用我的TypedMap。简而言之,它为您提供了一个类型安全的映射,它可以将任何类型的对象存储为键下的值:

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 );

为了让您快速访问键入的键,我建议使用枚举:

enum Key {
    Name(1) { @Override public TypedMapKey<String> getKey() { return NAME_KEY; },
    ...;

    private static Key[] byIndex = new Key[MAX_INDEX+1];
    static {
        for( Key key : values() ) { byIndex[key.index] = key; }
    }

    public static byIndex(int index) {
        return byIndex[index]; // I suggest non-null checks here if you have gaps
    }

    private Key(int index) {
        this.index = index;
    }

    public TypedMapKey<?> getKey() { throw new UnsupportedOperationException( "Please override"; ) }
}
于 2013-10-09T07:57:19.197 回答
0

创建一个简单的类来保存数据,并使用支持字段制作类似NameAge等 bean 的属性:

private int age; 

public getAge() { return age; } 

public setAge(int value) { age = value; }

制作一个名为的自定义注释@FieldInfo,其中包含一个字段序号和一个字段描述:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)    
public @interface FieldInfo {
    int ordinal();
    String description();
}

用您的注释装饰数据类:

@FieldInfo(ord=1, description="Age")
private int age; 

public getAge() { return age; } 

public setAge(int value) { age = value; }

为您的数据类创建一个基类,其中包含可以使用字段序号获取/设置值的通用方法get()set()方法,以及返回给定序号的字段描述的 getDescription() 方法。使用反射this.getClass().getDeclaredFields()获取Fields[],然后使用Field.getAnnotation(FieldInfo.class)获取每个字段的注解。

由于数据类属性在运行时不会更改,因此如果您经常使用序数访问字段,您可以在静态构造函数中为每个数据类类型构建两个静态查找<int, Field><int, String>加快处理速度。使用这种方法,您可以通过扩展注释来进一步描述字段,并且您的数据类仍然是具有传统 getter/setter 的简单类。

于 2013-10-09T08:45:13.403 回答
0

更新这是我的明确答案:

您在索引、描述和与之关联的值类型之间存在静态关系。所以让我们在一个类中捕捉到这一点:

public class Key<VALUETYPE> {
    private final Integer          index;
    private final String           description;
    private final Class<VALUETYPE> valueType;

    public Key(final Integer index, final String description, final Class<VALUETYPE> valueType) {
        super();
        this.index = index;
        this.description = description;
        this.valueType = valueType;
    }

    public Integer getIndex() {
        return index;
    }

    public String getDescription() {
        return description;
    }

    public Class<VALUETYPE> getValueType() {
        return valueType;
    }

    @Override
    public int hashCode() {
        return index.hashCode();
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj) { return true; }
        if (obj == null) { return false; }
        if (getClass() != obj.getClass()) { return false; }
        Key<?> other = (Key<?>) obj;
        return index.equals(other.index);
    }
}

我假设索引是键的唯一标识符,所以基于hashCodeequals

现在您编写一个涵盖您的用例的访问器类:

public class MapAccessor {
    private final Map<Integer, Key<?>> keyMap;
    private final Map<Key<?>, Object>  valueMap;

    public MapAccessor(final Map<Integer, Key<?>> keysByIndex, final Map<Key<?>, Object> valueMap) {
        this.keyMap = keysByIndex;
        this.valueMap = valueMap;
    }

    public void put(final Integer index, final Object value) {
        Key<?> key = keyMap.get(index);
        if (key.getValueType().isInstance(value) || value == null) {
            valueMap.put(key, value);
        }
        else {
            throw new IllegalArgumentException("Wrong type of value for index " + index + ", expected: " + key.getValueType()
                    + ", actual: " + value.getClass());
        }
    }

    public <VALUETYPE> VALUETYPE get(final Key<VALUETYPE> key) {
        return key.getValueType().cast(valueMap.get(key));
    }

    public Object get(final Integer index) {
        Key<?> key = getKey(index);
        return key == null ? null : get(key);
    }

    public Key<?> getKey(final Integer index) {
        return keyMap.get(index);
    }

    public String getDescription(final Integer index) {
        Key<?> key = getKey(index);
        return key == null ? null : key.getDescription();
    }
}

或者,您可以将其放在子类中,HashMap<Key<?>, Object>而不是委托给它。

让我们演示如何使用上述内容。请注意,对于按索引查找,强制转换是不可避免的。

public class ExampleUsage {
    private static final Key<String>   NAME  = new Key<>(1, "Name", String.class);
    private static final Key<Integer>  AGE   = new Key<>(2, "Age", Integer.class);

    private static final Map<Integer, Key<?>> keysByIndex = buildKeysByIndex(NAME, AGE);

    public static void main(final String... args) {
        Map<Key<?>, Object> valueMap = new HashMap<>();

        MapAccessor accessor = new MapAccessor(keysByIndex, valueMap);

        accessor.put(1, "Jasmine");
        String nameByIndex = (String) accessor.get(1); // returns "Jasmine", cast can't be avoided
        String nameByKey = accessor.get(NAME); // returns "Jasmine", no cast necessary
        Key<?> nameKeyByIndex = accessor.getKey(1); // returns NAME
        String nameDescriptionByIndex = accessor.getDescription(1); // returns "Name"

        accessor.put(2, 32);
        Integer ageByIndex = (Integer) accessor.get(2); // returns 32, cast can't be avoided
        Integer ageByKey = accessor.get(AGE); // returns 32, no cast necessary
        Key<?> ageKeyByIndex = accessor.getKey(2); // returns AGE
        String ageDescriptionByIndex = accessor.getDescription(2); // returns "Age"
    }

    private static Map<Integer, Key<?>> buildKeysByIndex(final Key<?>... keys) {
        Map<Integer, Key<?>> keyMap = new HashMap<Integer, Key<?>>();
        for (Key<?> key : keys) {
            keyMap.put(key.getIndex(), key);
        }
        return Collections.unmodifiableMap(keyMap);
    }
}
于 2013-10-09T08:19:16.703 回答