【发布时间】:2017-09-27 16:37:38
【问题描述】:
我正在研究创建代理对象的库是如何工作的,特别是我想了解它们如何从声明的方法中获取类型。例如适用于 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 中,有一些具体化的泛型,它们在编译时看起来像是一些 hack,但我们可以很容易地从泛型中获取类:
inline fun <reified T> test() {
print(T::class)
}
现在我完全对类型擦除机制感到困惑。
- 谁能解释一下,为什么有时它包含信息而有时却没有?
- 为什么泛型没有在 Java 中以正常方式实现?是的,我读到它可能会破坏与以前版本的兼容性,但我想了解如何。为什么泛型返回类型除了
new ArrayList<Integer>does 不会破坏任何东西? - 为什么匿名类拥有泛型类型而不是类型擦除?
更新: 4. reified generics 在 Kotlin 中是如何工作的,为什么这么酷的东西不能在 Java 中实现?
Here 非常清楚地解释了具体化泛型是如何工作的。 @Mibac
您只能将 reified 与内联函数结合使用。这样的 函数使编译器将函数的字节码复制到每个 使用函数的地方(函数被 “内联”)。当您调用具有具体类型的内联函数时, 编译器知道用作类型参数的实际类型并修改 生成的字节码直接使用对应的类。 因此,像 myVar is T 这样的调用变成 myVar is String,如果类型 参数是字符串,在字节码和运行时。
【问题讨论】: