我正在调查创建代理对象的库是如何工作的,特别是我想了解它们如何从声明的方法中获取类型。例如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)
}
现在我对类型擦除机制感到困惑。
new ArrayList<Integer>
之外,为什么泛型返回类型不会破坏任何东西? 更新 4.如何在Kotlin中使用具体化的泛型,以及为什么这些很酷的东西不能用Java实现?
Here非常明确地阐明了仿制药的工作原理。的 @Mibac
您只能将reified与内联函数结合使用。这样 函数使编译器将函数的字节码复制到每个字节码 正在使用该功能的地方(该功能正在使用 &#34;内联&#34)。当您使用reified类型调用内联函数时, 编译器知道用作类型参数的实际类型并进行修改 生成的字节码直接使用相应的类。 因此像myVar这样的调用是T成为myVar的String,如果是类型的话 参数是String,在字节码和运行时。
答案 0 :(得分:3)
有人可以解释一下,为什么有时它会保存信息而有时却没有?
在jvm级别上有一个Signature attribute:
为类,接口,构造函数,方法或字段记录签名(第4.7.9.1节),其声明在Java编程语言中使用类型变量或参数化类型。
您可能希望拥有它的原因之一是,例如,编译器需要知道来自预编译some_method
(来自第三方)的some.class
的实际参数类型some.jar
)。在此方案中,假设方法花费Object
可能违反编译some.class
的假设,并且您无法以类型安全的方式调用some_method
。
为什么匿名类包含泛型类型而不是类型擦除?
致电时:
System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass());
......根据 jvm classes ,没有任何定义,而这是:
System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass());
...实际上在 jvm级别上定义了类,在 java laguage级别上匿名为albiet。
这就是为什么反射会给这些案例带来不同结果的原因。
为什么在Java中没有以正常方式实现泛型?是的,我读到它可能会破坏先前版本的兼容性,但我想了解如何。除了新的ArrayListdoes之外,为什么泛型返回类型不会破坏任何东西?
如何在Kotlin中使用具体化的泛型以及为什么这些很酷的东西不能用Java实现?
我认为你不能给出那些不以意见为基础的客观答案。此外,我建议拆分或缩小问题的范围。