我想知道在类型擦除之后可以使用什么工具来查看代码。例如,在类型擦除之后,我想看看下面的代码是什么样子的。我知道在最终编译之前会删除泛型类型信息,用对象或边界类型替换类型引用,创建桥方法等等。我希望在擦除过程发生后看到源代码。
public static void main(String[] args) {
Predicate<Object> objPredicate = (Object c) -> c.toString().length() > 2 ;
Predicate<? super Integer> predicate = objPredicate;
Number n = Integer.valueOf(22);
System.out.println(predicate.test(n)); //this line does not compile
}如果需要编译代码才能在示例中看到擦除检查工具的工作,则可以省略非编译行或将n转换为Integer。
发布于 2021-06-09 14:41:26
在github上,我找到了基于java的开源gui工具字节码查看器,它完成了如下工作:
public static void main(String[] var0) {
Predicate var1 = (var0x) -> {
return var0x.toString().length() > 2;
};
Integer var3 = 22;
System.out.println(var1.test(var3));
}为此,我将视图菜单设置为Pane 2/Fern花/Java。
发布于 2021-06-08 23:55:38
我知道,泛型类型信息在最终编译之前就被删除了。
这并不完全正确,因为擦除是编译过程本身的一部分,而不是编译之前发生的事情。也就是说,擦除并不是发生在源代码上的转换。
因此,没有办法(据我所知)以编程方式获得源代码的转换版本,但通过遵循JLS 4.6中的规则,我们可以了解这样的简单示例会发生什么。
类型擦除是从类型(可能包括参数化类型和类型变量)到类型(从来不是参数化类型或类型变量)的映射。对于类型T的擦除,我们编写了_~_
类型擦除还将构造函数或方法的签名(§8.4.2)映射到没有参数化类型或类型变量的签名。构造函数或方法签名s的擦除是由与s相同的名称和s中给出的所有形式参数类型的擦除组成的签名。
如果删除方法或构造函数的签名,则方法的返回类型(§8.4.5)和泛型方法或构造函数的类型参数(§8.4.4,§8.8.4)也会被擦除。
删除泛型方法的签名没有类型参数。
对于我们得到的代码片段(忽略琐碎的擦除):
Predicate<Object> -> Predicate
Predicate<? super Integer> -> Predicate屈服:
public static void main(String[] args) {
Predicate objPredicate = (Object c) -> c.toString().length() > 2 ;
Predicate predicate = objPredicate;
Number n = Integer.valueOf(22);
System.out.println(predicate.test(n)); //this line does not compile
}此外,Predicate::test方法的擦除签名是:
boolean test(Object t)发布于 2021-06-09 01:12:58
如果您有一个非常简单的类型,如:
public static void main(String[] args) {
Predicate<? super Integer> predicate = x -> x > 1;
}它是用invokedynamic编译的,比如:
invokedynamic #7, 0 // InvokeDynamic #0:test:()Ljava/util/function/Predicate;如果您查看BootstrapMethods,MethodType保存(几乎)所有的泛型信息(我不认为它能够保留存在通配符的事实):
#41 (Ljava/lang/Integer;)Z它读为“接受一个整数,返回一个布尔值”。因此,从理论上讲,可以重新构建通用信息。我尝试过Intellij从.class文件中重构类型--而且它不保留泛型类型。我不知道有什么工具能做到这一点。
https://stackoverflow.com/questions/67895684
复制相似问题