How type erasure is erased

Iโ€™m learning how libraries that create proxy objects work, I want to understand how they extract types from declared methods. For example, a popular library for Android - Upgrade:

interface MyService { @GET("path") Call<MyData> getData(); } 

I was confused - how can I get exactly the MyData class from this interface, and not the raw Object? The reason from my understanding of type erasure will remove any information that fits inside common braces.

I wrote some test codes, and it is surprising to me that it is very easy to get a 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 little dirty, but it works and prints Integer . This means that we have types at runtime. I also 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 an ArrayList<Integer> .

And this is not the last thing that confused me. Kotlin has generic generics that look like hacked during compilation, but we can easily get a class from a generic one:

 inline fun <reified T> test() { print(T::class) } 

And now I'm completely confused with the type erase mechanism.

  • Can someone explain why sometimes it stores information and sometimes not?
  • Why are generics not implemented normally in Java? Yes, I read that this may break compatibility with previous versions, but I want to understand how to do this. Why doesn't the generic return type break anything other than new ArrayList<Integer> ?
  • Why do anonymous classes have a common type and are not erased?

Updated: 4. How are generic generics created in Kotlin and why such a cool thing cannot be implemented in Java?

This explains a fairly clear idea of โ€‹โ€‹how reconstituted generics work. @Mibac

You can only use reify in combination with the built-in function. such a function forces the compiler to copy the bytecode function to everyone where the function is used (the "Embed" function). When you call an inline function with type reified, the compiler knows the actual type used as the type argument and modifies the generated bytecode to use the corresponding class directly. Therefore, calls of type myVar: T becomes myVar - String, if the type of the argument was String, in bytecode and at run time.

+5
source share
1 answer

Can someone explain why sometimes it stores information and sometimes not?

At the jvm level, there is a Signature attribute, which:

records the signature (ยง4.7.9.1) for a class, interface, constructor, method or field whose declaration in the Java programming language uses type variables or parameterized types.

One of the reasons why you might want to do this is because, for example, the compiler needs to know the actual type of the some_method argument, which comes from the precompiled some.class (which comes from the third-party some.jar ), in this scenario, assuming that the method accepts Object may violate the assumptions with which some.class was compiled, and you cannot call some_method as types.

Why do anonymous classes have a common type and are not erased?

When you call:

 System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass()); 

... nothing is defined in terms of jvm classes, and this:

 System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass()); 

... actually defines a class at the jvm level, anonymous albiet at the jagu laguage level.

It is for this reason that reflection gives different results for these cases.

Why are generics not implemented normally in Java? Yes, I read that this may break compatibility with previous versions, but I want to understand how to do this. Why doesn't the return type break anything but the new ArrayListdoes?

How are generalized droids created in Kotlin and why such a cool thing cannot be implemented in Java?

I do not think that you can give an objective answer that is not based on opinions. Moreover, I would suggest either splitting or narrowing the scope of your question.

+3
source

Source: https://habr.com/ru/post/1272168/


All Articles