是否可以让javac
输出有关它为方法调用推断的类型的信息?
例如,我想知道T
的调用中正式类型bar
的推断内容。
private static <T> void bar() { ... }
public void foo() {
bar();
}
我正在探索javac -Xprint
和朋友,但无法找到任何能够揭示这一详细程度的内容。
编辑示例。我原本不打算把它放在原因,因为它会使答案复杂化。我主要想从javac
中获取调试信息。无论如何,这是一个激励的例子:
public class Scratch {
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t; // Warning: Type safety: Unchecked cast from Throwable to T
}
public void foo() {
sneakyThrow(new Exception());
}
}
这会编译,但对T
的实际类型的任何合理决定都应该产生Throwable
,并且需要foo() throws Throwable
。 Eclipse似乎认为它是RuntimeException
。我想知道javac
认为发生了什么。如果javac
处理throws
条款中的类型参数是一个错误,那么这个问题的答案将允许我证明它。
答案 0 :(得分:2)
可以详细查看javac推断/解决的内容等。为此,您需要使用隐藏/不支持/未记录的选项:-XDverboseResolution。如果想要查看所有信息,那么要传递的值是“all”,如:-XDverboseResolution = all。如果只想查看泛型方法的实例化,则选项为:-XDverboseResolution = deferred-inference。对于原始问题中的代码,我得到以下输出:
命令:javac -XDverboseResolution=deferred-inference Scratch.java
输出:
Scratch.java:6: Note: Deferred instantiation of method <T>sneakyThrow(Throwable)
sneakyThrow(new Exception());
^
instantiated signature: (Throwable)void
target-type: <none>
where T is a type-variable:
T extends Throwable declared in method <T>sneakyThrow(Throwable)
Note: Scratch.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
从这个输出中你可以推断T已经被实例化为Throwable。
我希望这就是你要找的东西。
答案 1 :(得分:0)
您要找的是 type erasure ,而不是类型推断。
我不知道javac
可以输出类型擦除详细信息的任何选项。
本质上,编译器将所有类型参数擦除到从类型参数派生的最低已知类型:
<T>
变为Object
<T extends Number>
变为Number
<T extends Comparable<T>>
变为Comparable
<T extends Cloneable & Comparable<T>>
变为Cloneable
<T extends Object & Comparable<T>>
变为Object
<S, T extends S>
变为Object,Object
您可以随时通过调用.class
来查看javap -c <class_name>.class
文件,以查看生成的字节代码是什么。
* N.B。请记住,编译器有各种开关,允许您保留调试信息。请参阅javac -g
选项。
因此,在下面的实验中,您的代码会稍微重做(注意类声明中的类型参数和sneakyThrow(T t) throws T
。
public class Scratch <T extends Throwable> {
private static <T extends Throwable> void sneakyThrow(T t) throws T {
throw (T) t;
}
public void foo() throws T {
sneakyThrow((T) new Exception());
}
}
...以下是使用javap -v -c Scratch.class
进行编译后javac -g:none Scratch.java
输出的一部分:
Constant pool:
#1 = Methodref #6.#19 // java/lang/Object."<init>":()V
#2 = Class #20 // java/lang/Exception
#3 = Methodref #2.#19 // java/lang/Exception."<init>":()V
#4 = Methodref #5.#21 // Scratch.sneakyThrow:(Ljava/lang/Throwable;)V
#5 = Class #22 // Scratch
#6 = Class #23 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 sneakyThrow
#11 = Utf8 (Ljava/lang/Throwable;)V
#12 = Utf8 Exceptions
#13 = Class #24 // java/lang/Throwable
#14 = Utf8 Signature
#15 = Utf8 <T:Ljava/lang/Throwable;>(TT;)V^TT;
#16 = Utf8 foo
#17 = Utf8 ()V^TT;
#18 = Utf8 <T:Ljava/lang/Throwable;>Ljava/lang/Object;
#19 = NameAndType #7:#8 // "<init>":()V
#20 = Utf8 java/lang/Exception
#21 = NameAndType #10:#11 // sneakyThrow:(Ljava/lang/Throwable;)V
#22 = Utf8 Scratch
#23 = Utf8 java/lang/Object
#24 = Utf8 java/lang/Throwable
public Scratch();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void foo() throws T;
Code:
0: new #2 // class java/lang/Exception
3: dup
4: invokespecial #3 // Method java/lang/Exception."<init>":()V
7: invokestatic #4 // Method sneakyThrow:(Ljava/lang/Throwable;)V
10: return
}
正如您所看到的,Throwable
是类型删除所确定的内容。