Is it possible to get javac
to output information about the types it's inferring for method invocations?
For example, I want to know what is inferred for the formal type T
in the invocation of bar
.
private static <T> void bar() { ... }
public void foo() {
bar();
}
I was exploring javac -Xprint
and friends, but can't find anything that exposes this level of detail.
EDIT Example. I didn't want to put this up originally because it'll complicate answers. I'm primarily interested in getting debug info out of javac
. Anyway, this was the motivating example:
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());
}
}
This compiles, but any reasonable decision as to the actual type of T
should yield Throwable
, and require that foo() throws Throwable
. Eclipse seems to think it's RuntimeException
. I want to know what javac
thinks is happening. If it's a bug in javac
's processing of type parameters in the throws
clause, the answer to this question would allow me to prove it.
It's possible to see with a lot of detail what javac has inferred / resolved etc. To do that you need to use the hidden / unsupported / undocumented option: -XDverboseResolution. If one want to see all the information then the value to pass is 'all' as in: -XDverboseResolution=all. If one only want to see the instantiation of the generic methods then the option is: -XDverboseResolution=deferred-inference. For the code in the original question I get the following output:
command: javac -XDverboseResolution=deferred-inference Scratch.java
output:
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.
From this output you can infer that T has been instantiated to Throwable.
I hope this is what you were looking for.
What are you looking for is type erasure as opposed to type inference .
I don't know of any option to javac
which would output type erasure details.
Essentially compiler erases all type parameters to the lowest known type derived from the type parameter:
<T>
becomes Object
<T extends Number>
becomes Number
<T extends Comparable<T>>
becomes Comparable
<T extends Cloneable & Comparable<T>>
becomes Cloneable
<T extends Object & Comparable<T>>
becomes Object
<S, T extends S>
becomes Object,Object
You can always inspect your .class
file by calling javap -c <class_name>.class
to see, what is the resulting byte code.
*NB Please keep in mind that compiler has various switches allowing you to preserve debug info. See javac -g
option.
So in terms of experiment below is your code slightly reworked (note type parameter in class declaration and 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());
}
}
... and below is part of the output of javap -v -c Scratch.class
after compiling it using 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
}
As you can see Throwable
is what type erasure settled on.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.