使用运行时给定的类型创建通用映射

时间:2014-03-16 20:40:16

标签: java generics reflection collections

标题可能有点难以理解,但让我简要描述一下我的问题。

我们假设我有一个这样的注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Identifier {

}

现在,我创建了一个用它来注释任何字段的类:

public class Student {
    private String name;
    private String surname;
    @Identifier
    private String idNumber;
    ...
}

最后,在运行时,我想创建一个Map,其密钥类型为typeof(field annotated with @Identifier),值类型为Student。请注意,任何字段都可以使用@Identifier进行注释。

有什么想法吗?

修改

好的,让我澄清一点:

class Student {
    private String name;
    private String surname;
    @Identifier
    private String idNumber;
}

class Foo {
    @Identifier
    private Integer x;
}

//  Now, what I want to have are two maps:

SortedMap students;     //  key type: String
                        //  value type: Student
SortedMap foos;         //  key type: Integer
                        //  value type: Foo

提前致谢!

2 个答案:

答案 0 :(得分:1)

我仍然不确定你想做什么。

  

在运行时我想创建一个键类型为typeof的Map(字段   用@Identifier注释)和学生的值类型

您可以创建原始MapMap<Object, Object>。您可以获取使用@Identifier注释的字段的类型。我不确定你的值类型的学生是什么意思所以我假设你的意思是类型Student,即。它的Class对象。

public static void main(String[] args) throws Exception {
    Class<?> clazz = Student.class;
    Map<Object, Object> map = new HashMap<>();
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        Identifier annotation = field.getAnnotation(Identifier.class);
        if (annotation != null) {
            map.put(field.getType(), clazz);
        }
    }
    System.out.println(map);
}

在您的问题中使用示例类,打印

{class java.lang.String=class com.spring.Student}

因此带注释的字段类型将映射到类类型。

虽然您在编译时不知道类型Map<String,Student>(甚至可能不是String),但您无法拥有Student。您可以尝试投射,但是您要为自己设置一些ClassCastException s。

答案 1 :(得分:0)

因此,您将获得一个方法(在我的示例中为myMethod),该方法将传递可能包含使用@Identifier注释的字段的对象。

很抱歉破解了你的泡泡但是没有办法在运行时保留通用信息。您可以获得的最接近的是Map<Field, Class<?>>,其中包含您所需类型的键值对。你就是这样做的:

public Map<Field, Class<?>> myMethod(Object obj) {
    Map<Field, Class<?>> result = new HashMap<Field, Class<?>>();
    for(Field field : obj.getClass().getDeclaredFields()) {
        Identifier identifier = field.getAnnotation(Identifier.class);
        if(identifier != null) {
            result.put(field, obj.getClass());
            return result;
        }
    }
    return result;
}

在我的示例中,结果将是空的MapMap,其中包含一个键值对。我建议你应该为结果使用单独的类型而不是Map。当然,如果您需要Field以外的其他内容,则可以篡改代码,例如,您可以使用Field getType()getGenericType()方法。