简体   繁体   English

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

[英]Create a generic map using type given at runtime

The title may be a bit hard to understand, but let me just briefly describe my problem. 标题可能有点难以理解,但让我简单地描述一下我的问题。

Let's assume I have an annotation like this: 我们假设我有一个这样的注释:

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

}

Now, I make a class which annotates any of its fields with it: 现在,我创建了一个用它来注释其任何字段的类:

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

Finally, at runtime I want to create a Map with the key type of typeof(field annotated with @Identifier) and the value type of Student . 最后,在运行时,我想创建一个键类型为typeof(field annotated with @Identifier)Map typeof(field annotated with @Identifier)和值类型Student Note that any field can be annotated with @Identifier . 请注意,任何字段都可以使用@Identifier进行注释。

Any ideas? 有任何想法吗?

EDIT 编辑

Ok, let me clarify this a bit: 好的,让我澄清一点:

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

Thanks in advance! 提前致谢!

I'm still not exactly sure what you want to do. 我还不确定你想做什么。

at runtime I want to create a Map with the key type of typeof(field annotated with @Identifier) and the value type of Student 在运行时我想创建一个键类型为typeof的Map(带有@Identifier注释的字段)和值类型Student

You can create a raw Map or a Map<Object, Object> . 您可以创建原始MapMap<Object, Object> You can get the type of the field annotated with @Identifier . 您可以获取使用@Identifier注释的字段类型。 I'm not sure what you mean by value type of Student so I'll assume you mean the type Student , ie. 我不确定你对学生价值类型是什么意思所以我认为你的意思是Student类型,即。 its Class object. 它的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);
}

With your example class in your question, this prints 在您的问题中使用您的示例类,这将打印出来

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

So the annotated field type is mapped to the class type. 因此,带注释的字段类型将映射到类类型。

You won't be able to have a Map<String,Student> though because you don't know the type String (and possibly not even Student ) at compile time. 您将无法拥有Map<String,Student>因为您在编译时不知道String类型(可能甚至不是Student )。 You can try casting, but you're setting yourself up for a number of ClassCastException s. 你可以尝试强制转换,但是你要为自己设置一些ClassCastException

So you are going to have a method ( myMethod in my example) which will be passed objects which may hold a field annotated with @Identifier . 因此,您将获得一个方法(在我的示例中为myMethod ),该方法将传递可能包含使用@Identifier注释的字段的对象。

Sorry to burst your bubble but there is no way to keep generic information at runtime. 很抱歉破解了你的泡泡但是没有办法在运行时保留通用信息。 The closest you can get is having a Map<Field, Class<?>> which holds key-value pairs with your desired type. 你可以得到的最接近的是Map<Field, Class<?>> ,它保存了你想要的类型的键值对。 This is how you do it: 这是你如何做到的:

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

In my example the result will either be an empty Map or a Map with one key-value pair. 在我的示例中,结果将是空Map或具有一个键值对的Map I suggest you should use a separate type for the result instead of a Map . 我建议您应该为结果使用单独的类型而不是Map Of course you can tamper with the code if you want something other than a Field for example you can use Field 's getType() or getGenericType() methods. 当然,如果你想要一个Field以外的东西,你可以篡改代码,例如你可以使用FieldgetType()getGenericType()方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM