JDK8 中的类型推断与重载解析(2)

然后是 desugar,看起来是不是挺像解除语法糖的。这个过程会对类进行变换。把 get() 的返回类型由 char[] 变为 Object 的过程,就在这个函数中。最终是由 com.sun.tools.javac.tree.TreeTranslator#translate(T) 这个函数完成。

其中函数 get 会被变换:

public static <T> T get() { return (T) "x"; }

会变成

public static Object get() { return (Object) "x"; }

同时,String.valueOf(get()) 中的 get() 方法,其类型 char[] 也会变成 Object。这个过程在 com.sun.tools.javac.comp.TransTypes#retype 中完成。

// tree: get(); erasedType: java.lang.Object; target: char[] JCExpression retype(JCExpression tree, Type erasedType, Type target) { .. }

由于 get() 返回类型为 T,所以这个函数会把 T 换成 Object,同时插入一条指令,将 Object 转换成 char[]。

retype 的本意如下面这个例子所示:

class Cell<A> { A value; } Cell<Integer> cell; Integer x = cell.value;

此时,会将 cell.value 返回值设置成 Object, 并且插入强制类型转换的指令。

但是在我们这次分析的情况中,get() 的返回类型 T 已经被推断出是 char[],为什么又因为其定义是 T,然后被擦除,变为 Object 呢?这样一来,String.valueOf 选择了 String.valueOf(char[]),而 get() 的类型是 Object,又要强制转化成 char[]。既然如此,为什么不选择 String.valueOf(Object) 呢?感觉像个 bug 啊。我现在也不能理解为什么要这么做。

最后是 generate,生成字节码。生成 get() 字节码的源代码位于 com.sun.tools.javac.jvm.Gen#genExpr,此时参数 tree 为 get(),pt 为 char[]。生成 get() 字节码时,其返回类型已为 Object,而非 char[]。

最后总结一下文中最开始时提到的两个问题:

对 get() 返回类型的推断

对 String.valueOf 这个重载方法的选择

在 JDK6 中

get() 返回类型直接设置为 Object

String.valueOf 选择了 String.valueOf(Object)

String.valueOf 与 get() 匹配

在 JDK8 中

get() 返���类型先设置为 DeferredAttr.DeferredType

遍历 String.valueOf 的方法,在满足条件的 String.valueOf(Object) 和 String.valueOf(char[]) 中选择更为具体的 String.valueOf(char[]),get() 的返回类型也为 char[]

get() 的返回类型在 desugar 阶段被擦除,设置为 Object,同时强制转为 char[]

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f36fe4789db37e0c387e5dee91027339.html