I am investigating how libraries that creates proxy objects work especially I want to understand how they fetch types from declared methods. For example popular library for Android - Retrofit:
interface MyService {
@GET("path")
Call<MyData> getData();
}
I was confused - how it is possible to get from this interface exactly MyData class not raw Object? Cause from my understanding type erasure will remove any information that placed inside generic braces.
I wrote some test code and surprisingly to me it is really easy to get type from such code:
@org.junit.Test
public void run() {
Method[] methods = Test.class.getDeclaredMethods();
Method testMethod = methods[0];
System.out.println(testMethod.getReturnType());
ParameterizedType genericType = ((ParameterizedType) testMethod.getGenericReturnType());
Class<Integer> clazz = (Class<Integer>) genericType.getActualTypeArguments()[0];
System.out.println(clazz);
}
interface Test {
List<Integer> test();
}
It looks a bit dirty but it works and prints Integer
. It means that we have types in runtime. Also I've read about another dirty trick with anonymous classes:
System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass());
prints raw AbstractList<E>
while this code
System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass());
prints ArrayList<Integer>
.
And it is not last thing that confused me. In Kotlin there are reified generics from which looks like some hack in compile time but we can easily get class from generic:
inline fun <reified T> test() {
print(T::class)
}
And now I am totally confused with type erasure mechanism.
- Can someone explain, why sometimes it holds information and sometimes doesn't?
- Why generics isn't implemented in normal way in Java? Yes, I read that it could break compabillity with previous versions, but I want to understand how. Why does generic return type not break anything but
new ArrayList<Integer>
does? - Why do anonymous classes hold generic type and are not type erasured?
Updated: 4. How do reified generics works in Kotlin and why such cool thing can't be implemented in Java?
Here explained pretty clear about how reified generics work. @Mibac
You can only use reified in combination with an inline function. Such a function makes the compiler copy the function's bytecode to every place where the function is being used (the function is being "inlined"). When you call an inline function with reified type, the compiler knows the actual type used as a type argument and modifies the generated bytecode to use the corresponding class directly. Therefore calls like myVar is T become myVar is String, if the type argument were String, in the bytecode and at runtime.
reified
works – Mibac