java - 类型删除的工作原理

标签 java generics jvm kotlin

我正在研究创建代理对象的库是如何工作的,特别是我想了解它们如何从声明的方法中获取类型。例如流行的 Android 库 - Retrofit:

interface MyService {

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

我很困惑——如何从这个接口(interface)中得到准确的 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)
}

现在我对类型删除机制完全感到困惑。

  1. 谁能解释一下,为什么有时它包含信息而有时却没有?
  2. 为什么泛型没有在 Java 中以正常方式实现?是的,我读到它可能会破坏与以前版本的兼容性,但我想了解如何。为什么泛型返回类型除了 new ArrayList<Integer> 什么都没有破坏做?
  3. 为什么匿名类持有通用类型而不是类型删除?

已更新: 4. 具体化的泛型在 Kotlin 中是如何工作的,为什么这么酷的东西不能在 Java 中实现?

Here非常清楚地解释了具体化泛型的工作原理。 @Mibac

You can only use reified in combination with an inline function. Such a function makes the compiler copy the function's bytecode to every place where the function is being used (the function is being "inlined"). When you call an inline function with reified type, the compiler knows the actual type used as a type argument and modifies the generated bytecode to use the corresponding class directly. Therefore calls like myVar is T become myVar is String, if the type argument were String, in the bytecode and at runtime.

最佳答案

Can someone explain, why sometimes it holds information and sometimes doesn't?

在 jvm 级别上有一个 Signature attribute那:

records a 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.

您可能想要它的原因之一是,例如,编译器需要知道 some_method 的实际参数类型来自预编译的 some.class (来自第三方 some.jar )。在这种情况下,假设该方法采用 Object可能违反假设 some.class已编译,您不能调用 some_method以类型安全的方式。

Why do anonymous classes hold generic type and are not type erasured?

当你打电话时:

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

...jvm 类 没有任何定义,而这:

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

...实际上在jvm 级别 定义类,在java 语言级别 是匿名的。

这就是反射在这些情况下给出不同结果的原因。

Why generics isn't implemented in normal way in Java? Yes, I read that it could break compabillity with previous versions, but I want to understand how. Why does generic return type not break anything but new ArrayListdoes?

How do reified generics works in Kotlin and why such cool thing can't be implemented in Java?

我认为你不能给出不基于意见的客观答案。此外,我建议拆分或缩小您的问题范围。

关于java - 类型删除的工作原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46453054/

相关文章:

java - Android 没有应用程序可以执行此操作

java - 在 GridBagLayout 中展开 JTextArea

scala - Scala(或 JVM)是​​否曾经优化过(函数)对象?

java - 有关于 Raspberry PI 的 Java 经验吗?

java - Android 比例动画 - 反转问题

java - 为什么我不能使用带有通配符的多个类型参数?

java - 如何在 <base type> 的列表中查找并返回 <derived type> 的对象?

c# - 在C#中使用Lambda确定非相等属性值

java - 如果boolean在JVM中表示为int,那么它与Java的强类型是如何对应的呢?

java - TableView 和映射。字符和整数