[英]Is there a way to tell if the runtime type was erased
這將是一個有點復雜的解釋,但我會嘗試。
假設您有一個通用 class:
static class Box<T extends Number> {
private T value;
public T getValue() {
return value;
}
public void setValue(T value) {
this.value = value;
}
}
還有一個允許以反射方式調用getValue
的方法:
// it's just an example, the real world scenario is slightly more involved
private static final Lookup LOOKUP = MethodHandles.lookup();
public static <T, R> T result(String methodName, Class<T> propertyClass, R instance) {
try {
/* line1 */
MethodHandle handle = LOOKUP.findVirtual(
instance.getClass(),
methodName,
MethodType.methodType(propertyClass)
);
/* line2 */
handle = handle.asType(handle.type()
.changeReturnType(Object.class)
.changeParameterType(0, Object.class));
/* line3 */
Object obj = handle.invokeExact(instance);
return propertyClass.cast(obj);
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
這是做什么的
為getValue
方法創建一個MethodHandle
調整MethodHandle
,以便我可以在其上調用invokeExact
(否則我需要調用invoke
,這會更慢)。 但這一步完全是可選的。
一旦我構建了MethodHandle
,就調用它。
現在讓我們嘗試調用它:
public static void main(String[] args) throws Throwable {
Box<Long> box = new Box<>();
box.setValue(42L);
result("getValue", Long.class, box);
}
這應該有效,對吧? 嗯,沒有。 這將失敗:
Caused by: java.lang.NoSuchMethodException: no such method: GenericTest$Box.getValue()Long/invokeVirtual
我明白為什么,因為T extends Number
的擦除類型是Number
,所以調用應該是:
result("getValue", Number.class, box); // not Long.class
這對我來說是顯而易見的,但對我工作場所圖書館的來電者來說卻不是,我不能責怪他們。 請注意,這是一個簡化的示例...
當他們構建Box<Long> box = new Box<>();
對於Long
類型,提供Long.class
是很自然的,而不是Number.class
。 解決方案顯然是微不足道的,但是,我在想,如果我可以(在運行時)“看到” getValue
的返回類型是泛型類型,我可以拋出一個正確的錯誤消息。 例如:
"you provided Long.class, but the generic type was erased to ..."
換句話說,如果我可以在運行時告訴我返回類型是來自getValue
的Number.class
並且它是一些擦除的結果,那么我在以后的決定中可能會更聰明一些。
那可能嗎?
好吧,也許你可以使用好的舊反射。 使用反射允許您通過名稱和參數類型而不是返回類型來查找方法。 然后,您可以檢查返回類型以查看調用者是否提供了正確的類型:
Method method = instance.getClass().getMethod(methodName);
Class<?> rtype = method.getReturnType();
if (rtype != propertyClass) {
throw new IllegalArgumentException("must use " + rtype + " instead of " + propertyClass);
}
MethodHandle handle = LOOKUP.unreflect(method);
您可能需要根據需要調整反射查找(getMethod 或 getDeclaredMethod)的方式。 您可能還需要檢查以確保匹配的方法不是抽象的或 static。 (有人會認為它不能是抽象的,因為您提供了一個實例,但可能存在我沒有想到的邊緣情況,例如單獨編譯。)您可能還需要檢查該方法是否聲明在您正在反映的相同 class 。 由於您關心性能,因此進行反射可能會太慢。 但是,如果您只關心診斷,您可以嘗試快樂的路徑,如果您獲得 NSME,請進行反射查找以獲得正確的返回類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.