类型擦除如何工作
我正在研究如何创建代理对象的库,特别是我想了解如何从声明的方法获取类型。 例如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中实现? 是的,我读到它可以打破以前的版本compabillity,但我想了解如何。 为什么泛型返回类型不会破坏
new ArrayList<Integer>
呢? - 为什么匿名类持有泛型类型,而不是类型擦除?
更新: 4. Kotlin中的泛化泛型如何工作,以及为什么这种很酷的东西不能在Java中实现?
这里解释了如何泛化泛型工作的相当清楚。 @Mibac
你只能使用与内联函数结合使用。 这样的函数使编译器将函数的字节码复制到函数正在被使用的每个地方(函数被“内联”)。 当您使用具体化类型调用内联函数时,编译器知道用作类型参数的实际类型,并修改生成的字节码以直接使用相应的类。 因此,像myVar这样的调用是T成为myVar是字符串,如果类型参数是字符串,在字节码和运行时。
有人能解释一下,为什么有时候会有信息,有时却不会呢?
在jvm级别上有一个Signature属性 :
为Java编程语言中声明使用类型变量或参数化类型的类,接口,构造函数,方法或字段记录签名(第4.7.9.1节)。
你可能想要的一个原因是,例如,编译器需要知道来自预编译的some.class
(来自第三方some.jar
)的some_method
参数的实际类型。 在这种情况下,假设该方法采取Object
可能违反与some.class
编译的假设,你不能以类型安全的方式调用some_method
。
为什么匿名类持有泛型类型,而不是类型擦除?
你打电话时:
System.out.println(new ArrayList<Integer>().getClass().getGenericSuperclass());
…什么都没有被定义为jvm类 ,而这个:
System.out.println(new ArrayList<Integer>() { }.getClass().getGenericSuperclass());
…实际上在java语言级别上定义类,albiet匿名。
这就是为什么反射给这些情况带来不同结果的原因。
为什么泛型没有以正常的方式在Java中实现? 是的,我读到它可以打破以前的版本compabillity,但我想了解如何。 为什么泛型返回类型不会破坏新的ArrayList?
Kotlin中的泛化泛型如何工作,以及为什么这种很酷的东西不能在Java中实现?
我不认为你可以给客观的答复,这不是基于意见的。 此外,我建议要么分裂或缩小你的问题的范围。