[英]mix generic type variables to implement a type-safe map function in Java
我想在Java中編寫一個類型安全的map
方法,它返回一個與傳遞的參數相同類型的Collection(即ArrayList,LinkedList,TreeSet等)但是具有不同的泛型類型(在有角度的括號之間),確定通過另一個參數的泛型類型(通用映射函數的結果類型)。
所以代碼將用作:
public interface TransformFunctor<S, R> {
public R apply(S sourceObject);
}
TransformFunctor i2s = new TransformFunctor<Integer, String>() {
String apply(Integer i) {return i.toString();};
ArrayList<Integer> ali = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4));
ArrayList<String> als = map(ali, i2s);
TreeSet<Integer> tsi = new TreeSet<Integer>(Arrays.asList(1, 2, 3, 4));
TreeSet<String> tss = map(tsi, i2s);
這個想法是這樣的:
public static <C extends Collection<?>, S, R>
C<R> map(final C<S> collection, final TransformFunctor<S, R> f)
throws Exception {
//if this casting can be removed, the better
C<R> result = (C<R>) collection.getClass().newInstance();
for (S i : collection) {
result.add(f.apply(i));
}
return result;
}
但這不起作用,因為編譯器不希望泛型類型變量進一步專門化(我認為)。
有關如何使這項工作的任何想法?
似乎無法在泛型類型上使用泛型類型。 由於您只需要有限數量的那些,您可以枚舉它們:
public static <CS extends Collection<S>, CR extends Collection<R>, S, R> CR map(
final CS collection, final TransformFunctor<S, R> f)
throws Exception {
// if this casting can be removed, the better
CR result = (CR) collection.getClass().newInstance();
for (S i : collection) {
result.add(f.apply(i));
}
return result;
}
我使用CS
作為源集合, CR
作為結果集合。 我擔心你無法刪除演員,因為你不能在運行時使用泛型。 newInstance()
只是創建一個Object類型的對象,並且為了滿足編譯器,需要轉換為CR
。 但它仍然是一種欺騙。 這就是編譯器發出警告的原因,你必須使用@SuppressWarnings("unchecked")
來抑制。
有趣的問題btw。
你想做什么是不可能的。 但是,您可以指定返回集合的泛型類型。
public static <S, R> Collection<R> map(Collection<S> collection, TransformFunctor<S,R> f) throws Exception {
Collection<R> result = collection.getClass().newInstance();
for (S i : collection) {
result.add(f.apply(i));
}
return result;
}
這確實返回了您使用參數指定的類型的集合,它不會顯式地這樣做。 但是,將方法返回轉換為參數的集合類型是安全的。 但是,您應該注意,如果您傳遞的集合類型沒有no-arg構造函數,則代碼將失敗。
然后你可以像這樣使用它:
ArrayList<Integer> ali = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4));
ArrayList<String> als = (ArrayList<String>) map(ali, i2s);
TreeSet<Integer> tsi = new TreeSet<Integer>(Arrays.asList(1, 2, 3, 4));
TreeSet<String> tss = (TreeSet<String>) map(tsi, i2s);
這有效:
class Test {
public static void main(String[] args) throws Exception {
Function<Integer, String> i2s = new Function<Integer, String>() {
public String apply(Integer i) {
return i.toString();
}
};
ArrayList<Integer> ali = new ArrayList<Integer>(Arrays.asList(1, 2, 3,
4));
ArrayList<String> als = map(ali, i2s);
TreeSet<Integer> tsi = new TreeSet<Integer>(Arrays.asList(1, 2, 3, 4));
TreeSet<String> tss = map(tsi, i2s);
System.out.println(""+ali+als+tss);
}
static <SC extends Collection<S>, S, T, TC extends Collection<T>> TC map(
SC collection, Function<S, T> func) throws Exception {
// if this casting can be removed, the better
TC result = (TC) collection.getClass().newInstance();
for (S i : collection) {
result.add(func.apply(i));
}
return result;
}
}
interface Function<S, R> {
R apply(S src);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.