Скажем, есть тип фреймворка Row
с несколькими параметрами типа и метод, который работает с экземплярами типа Row
и использует все эти параметры типа.
У меня есть метод, который работает слюбой тип Row
, даже разные типы одновременно, поэтому, очевидно, я использую подстановочный тип Row<?,?>
.Вопрос в том, как мне вызвать метод, который принимает Row<R,K>
с Row<?,?>
?
Моя точка зрения: я точно не знаю, что такое тип Row<?,?>
, но это, безусловно, какой-товроде Row
хорошо.И когда универсальный метод принимает Row<R,K>
, это означает, что он хочет что-то сделать с R
и K
, но в противном случае он может иметь дело с любым типом Row
.Так что мой «любой» тип должен работать с методом, который принимает «любой» тип, верно?
Я прилагаю приведенный ниже пример кода с вещами, которые я пробовал.Самое странное, что последняя строка на самом деле работает, но она не более безопасна, чем все остальное, я думаю.Поэтому, в принципе, я бы хотел найти более чистое решение, чем это, если это возможно, или объяснение, почему это так.
package foo;
public class Experiment {
// Defined by a framework.
interface Key<K extends Key<K>> {}
interface Row<R extends Row<R, K>, K extends Key<K>> {}
static <R extends Row<R, K>, K extends Key<K>> R copyRow(R row) {
return row;
}
// My experiments below.
static class Wrapper<R extends Row<R, K>, K extends Key<K>> {
public final R row = null; // fixme
public final Class<R> clazz = null; // fixme
}
static <R extends Row<R, K>, K extends Key<K>> R upcast(Row<?, ?> row) {
return (R) row;
}
static <R extends Row<R, K>, K extends Key<K>> R upcast(Row<?, ?> row, Class<R> clazz) {
assert row.getClass().equals(clazz);
return (R) row;
}
public static void main(String[] args) {
Wrapper<?, ?> wr = null; // fixme
copyRow(wr.row); // Compilation error
copyRow(upcast(wr.row)); // Compilation error
copyRow(upcast(wr.row, wr.clazz)); // This works, why?
}
}
(Вы можете отправить этот пример прямо в javac, чтобы посмотреть, что произойдет. С Java 1.8: https://pastebin.com/LB10ySsD)