Reputation: 20396
I need to acquire the Constructor of a class at runtime using reflection instead of direct access. For simple types, this is trivial:
public class MyType {
public MyType(String a, Integer b, Long c) {}
}
Constructor constructor = MyType.class.getConstructor(String.class, Integer.class, Long.class);
But if the class uses generics as part of its arguments, it's not clear what I should put:
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*/);
I can write something like MyType.class.getConstructor(Set.class, Integer.class, List.class);
but it's not clear that that will achieve the behavior I want. What's the correct way to write this kind of code?
Upvotes: 0
Views: 63
Reputation: 5843
The generic information is not part of the information that is used by the getConstructor
method. The call you denoted (Set.class, ...
) is correct, as it resembles the information available at runtime.
As noted by Andy Turner, you can only have one constructor with this type - even if you try to use different generic arguments for a second constructor in your source code.
If you're curious, you can have a look at the bytecode using 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
}
Upvotes: 1
Reputation: 886
There is a way to acquire the constructor you need using reflections, but in this case is more complicated that it seems. You must check all the constructors of the class and all their parameters. Something like this:
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;
}
However, as noted by Andy Turner in the comments, you cannot create another constructor with the parameters with the same erasure (Set.class, Integer.class, List.class)
.
Upvotes: 0