如何正确查询具有通用参数的构造函数

时间:2017-06-15 20:16:20

标签: java reflection

我需要在运行时使用反射而不是直接访问来获取类的构造函数。对于简单类型,这是微不足道的:

public class MyType {
    public MyType(String a, Integer b, Long c) {}
}

Constructor constructor = MyType.class.getConstructor(String.class, Integer.class, Long.class);

但如果班级使用泛型作为其论点的一部分,那么我不清楚应该放什么:

public class MyType {
    public MyType(Set<String> a, Integer b, List<Long> c) {}
}

Constructor constructor = MyType.class.getConstructor(Set<String>.class /*Doesn't compile*/, Integer.class, List<Long>.class /*doesn't compile*/);

我可以写一些类似MyType.class.getConstructor(Set.class, Integer.class, List.class);的内容,但不清楚这会实现我想要的行为。编写这种代码的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

通用信息不是getConstructor方法使用的信息的一部分。您表示的调用(Set.class, ...)是正确的,因为它类似于运行时可用的信息。

正如Andy Turner所指出的,你只能有一个这种类型的构造函数 - 即使你试图在源代码中为第二个构造函数使用不同的泛型参数。

如果您有点好奇,可以使用javap查看字节码:

$ javap -private -c MyType
Compiled from "MyType.java"
public class MyType {
  public MyType(java.lang.String, java.lang.Integer, java.lang.Long);
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
}

答案 1 :(得分:0)

有一种方法可以使用反射获取所需的构造函数,但在这种情况下看起来更复杂。您必须检查类的所有构造函数及其所有参数。像这样:

public Constructor getConstructor() {
    Constructor constructor = null;
    Constructor<?>[] constructors = MyType.class.getConstructors();
    for(Constructor constructor1 : constructors) {
        Type[] types = constructor1.getGenericParameterTypes();
        if(types.length == 3) {
            if(types[0] instanceof ParameterizedType
                    && types[1].equals(Integer.class)
                    && types[2] instanceof ParameterizedType) {
                ParameterizedType type0 = (ParameterizedType) types[0];
                ParameterizedType type2 = (ParameterizedType) types[2];
                if(type0.getActualTypeArguments().length == 1 
                        && type0.getRawType().equals(Set.class)
                        && type0.getActualTypeArguments()[0].equals(String.class)
                        && type2.getActualTypeArguments().length == 1
                        && type2.getRawType().equals(List.class)
                        && type2.getActualTypeArguments()[0].equals(Long.class)) {
                    return constructor;
                }
            }
        }
    }
    return null;
}

但是,正如Andy Turner在评论中所指出的那样,您无法使用具有相同擦除(Set.class, Integer.class, List.class)的参数创建另一个构造函数。