簡體   English   中英

Java泛型參數類型不匹配,從類泛型到方法泛型

[英]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。 我正在使用另一種方法來創建它,該方法采用方法通用PClass<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM