[英]Java Generics Argument Type mismatch going from class generic to method generic
我有一個抽象類,它具有類級別的通用類型<O, P>
。 在其中,我有一個接受O
的方法,以及一個BiFunction<B, Class<B>, String>
。 <B>
泛型在方法上定義。
public interface ParamDescription<O, P> {
//...
<B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString);
}
然后,我有三個類以不同的方式實現該接口,但是它們都具有Class<O>
和Class<P>
變量。 兩個也有一些額外的類級泛型類型,以及與它們一起使用的Class<>
變量。 在所有這些方法中,我試圖使用一種類級別的泛型類型及其關聯的類變量的對象來調用objectToString方法。
這是最簡單的一個:
Function<? super O, P> getter;
Class<P> paramClass;
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
return objectToString.apply(getter.apply(obj), paramClass);
}
但是,當我嘗試編譯它時,我得到了:
error: method apply in interface BiFunction<T,U,R> cannot be applied to given types;
return objectToString.apply(getter.apply(obj), paramClass);
^
required: B,Class<B>
found: P,Class<P>
reason: argument mismatch; P cannot be converted to B
where B,O,P,T,U,R are type-variables:
B extends Object declared in method <B>getParamString(O,BiFunction<B,Class<B>,String>)
O extends Object declared in class ParamDescriptionSingle
P extends Object declared in class ParamDescriptionSingle
T extends Object declared in interface BiFunction
U extends Object declared in interface BiFunction
R extends Object declared in interface BiFunction
在此示例中,我可以通過將B
更改為P
來解決。 但是,這不適用於其他兩個實現。 在其他兩種實現中,我需要使用一些接口不知道的通用類型。
我唯一真正的限制是提供給BiFunction的Class<B>
參數應該對應於也提供給它的B
參數。 基本上,“這是一個對象,這是它的類型”。
我試圖創建一個像這樣的輔助函數
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
return paramToString(obj, objectToString);
}
public String paramToString(O obj, BiFunction<P, Class<P>, String> objectToString) {
return objectToString.apply(getter.apply(obj), paramClass);
}
但它不喜歡在BiFunction上進行強制轉換。
我也嘗試過這樣的實際轉換:
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
return objectToString.apply((B)getter.apply(obj), (Class<B>)paramClass);
}
但這給兩個演員都提供了未經檢查的演員警告,而且我還不知道它是否真正安全。 我的理解是,它基本上只會將第一件事投給Object,然后將第二件事投給Class。
是發布和禁止警告的方式還是更好的方法?
供參考,這是我的其他兩個實現:
//Class level: <O, E, P extends Collection<? extends E>>
Class<O> objClass;
Class<P> paramClass;
Class<E> entryClass;
Function<? super O, P> getter;
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
P collection = getter.apply(obj);
if (collection == null) {
return objectToString.apply(collection, paramClass);
}
return collection.stream()
.map(e -> objectToString.apply(e, entryClass))
.collect(Collectors.toList())
.toString();
}
和
//Class level: <O, K, V, P extends Map<? extends K, ? extends V>>
Class<O> objClass;
Class<P> paramClass;
Class<K> keyClass;
Class<V> valueClass;
Function<? super O, P> getter;
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
P map = getter.apply(obj);
if (map == null) {
return objectToString.apply(map, paramClass);
}
return map.entrySet()
.stream()
.collect(Collectors.toMap(e -> objectToString.apply(e.getKey(), keyClass),
e -> objectToString.apply(e.getValue(), valueClass)))
.toString();
}
更新1中有我嘗試過的更多操作,但無效:
我嘗試設置目標:
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
return objectToString.<P>apply(getter.apply(obj), paramClass);
}
但這仍然給
required: B,Class<B>
found: P,Class<P>
reason: argument mismatch; P cannot be converted to B
我嘗試使用通配符代替B
:
public String getParamString(O obj, BiFunction<?, Class<?>, String> objectToString) {
return objectToString.apply(getter.apply(obj), paramClass);
}
結果相同:
required: CAP#1,Class<?>
found: P,Class<P>
reason: argument mismatch; P cannot be converted to CAP#1
看起來顯式強制轉換和禁止警告可能是唯一的方法。
@SuppressWarnings("unchecked")
public <B> String getParamString(O obj, BiFunction<B, Class<B>, String> objectToString) {
return objectToString.apply((B)getter.apply(obj), (Class<B>)paramClass);
}
但是,這令人沮喪,因為我隨后失去了編譯時檢查,無法確保所提供的類(第二個參數)代表第一個參數的類。 但是它確實起作用,否則它的行為正確。
我使用的更新2由於強制轉換是我可以使其真正起作用的唯一方法,並且消除了上面提到的檢查,因此我決定完全擺脫通用類型B
我的界面有這個:
String getParamString(O obj, BiFunction<Object, Class, String> objectToString);
和我的實現如下所示:
public String getParamString(O obj, BiFunction<Object, Class, String> objectToString) {
return objectToString.apply(getter.apply(obj), paramClass);
}
和
public String getParamString(O obj, BiFunction<Object, Class, String> objectToString) {
P collection = getter.apply(obj);
if (collection == null) {
return objectToString.apply(collection, paramClass);
}
return collection.stream()
.map(e -> objectToString.apply(e, entryClass))
.collect(Collectors.toList())
.toString();
}
和
public String getParamString(O obj, BiFunction<Object, Class, String> objectToString) {
P map = getter.apply(obj);
if (map == null) {
return objectToString.apply(map, paramClass);
}
return map.entrySet()
.stream()
.collect(Collectors.toMap(e -> objectToString.apply(e.getKey(), keyClass),
e -> objectToString.apply(e.getValue(), valueClass)))
.toString();
}
然后,在調用這些函數時,我必須禁止顯示警告,但這是由於我如何創建BiFunction。 我正在使用另一種方法來創建它,該方法采用方法通用P
和Class<P>
,該方法將轉換為BiFunction的Object
和原始Class
。 我認為,這比每次使用BiFunction都要強制轉換和禁止警告要好。
總結:我做到了,但是我無法以提供所需保護的方式來做到這一點。
簡短答案:請勿在該方法上使用泛型B
詳細信息:除了強制轉換之外,沒有任何方法可以告訴編譯器,對於給定的調用,應將P
(或其他某種通用類型)視為B
:
return objectToString.apply((B)getter.apply(obj), (Class<B>)paramClass);
但是,由於要顯式進行強制轉換,因此無法保證所提供的類(第二個參數)代表第一個參數的類。 定義B
泛型類型的唯一目的是獲得此保護。 因此,最好不要在此處使用泛型,而應使該參數為BiFunction<Object, Class, String>
。
String getParamString(O obj, BiFunction<Object, Class, String> objectToString);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.