我正在调查创建代理对象的库是如何工作的,特别是我想了解它们如何从声明的方法中获取类型 . 例如Android的流行库 - Retrofit:
interface MyService {
@GET("path")
Call<MyData> getData();
}
我很困惑 - 如何才能从这个界面获得正确的MyData类而不是原始对象?我的理解类型擦除的原因将删除放置在通用大括号内的任何信息 .
我写了一些测试代码,令我惊讶的是从这样的代码获取类型真的很容易:
@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();
}
它看起来有点脏,但它工作和打印 Integer
. 这意味着我们在运行时有类型 . 此外,我已经阅读了有关匿名类的另一个脏技巧:
System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass());
在此代码中打印原始 AbstractList<E>
System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass());
打印 ArrayList<Integer>
.
这并不是让我困惑的最后一件事 . 在Kotlin中有一些具体的泛型,在编译时看起来像是一些黑客,但我们可以轻松地从泛型中获取类:
inline fun <reified T> test() {
print(T::class)
}
而现在我完全混淆了类型擦除机制 .
-
有人可以解释一下,为什么有时它会保存信息而有时却没有?
-
为什么在Java中没有以正常方式实现泛型?是的,我读到它可能会破坏先前版本的兼容性,但我想了解如何 . 除了
new ArrayList<Integer>
之外,为什么泛型返回类型不会破坏任何东西? -
为什么匿名类包含泛型类型而不是类型擦除?
Updated: 4.在Kotlin中如何使用具体化的泛型以及为什么在Java中无法实现这么酷的东西?
Here非常明确地说明了仿制药的工作原理 . @Mibac
您只能将reified与内联函数结合使用 . 这样的函数使得编译器将函数的字节码复制到每个使用函数的地方(函数被“内联”) . 当您使用reified类型调用内联函数时,编译器会知道用作类型参数的实际类型,并修改生成的字节码以直接使用相应的类 . 因此,像myVar这样的调用是T变为myVar是String,如果类型参数是String,则在字节码和运行时 .
1 回答
在jvm级别上有一个Signature attribute:
您可能希望拥有它的原因之一是,例如,编译器需要知道来自预编译
some.class
(来自第三方some.jar
)的some_method
的实际参数类型 . 在这种情况下,假设该方法采用Object
可能违反编译some.class
的假设,并且您无法以类型安全的方式调用some_method
.你打电话的时候:
......根据jvm类没有任何定义,而这个:
...实际上在jvm级别上定义了类,在java laguage级别上定义了albiet匿名 .
这就是为什么反射为这些情况提供不同结果的原因 .
我不认为你能给出客观的答案,而不是基于意见的答案 . 此外,我建议拆分或缩小问题的范围 .