Desculpas pelo título ruim. Eu apreciaria alguma ajuda para elaborar um melhor, mas nem sei como descrever meu problema.
Digamos que eu tenha os seguintes tipos.
interface M<K, V> {}
interface F<I, O> {}
E digamos que eu crie uma classe que implemente ambas as interfaces.
record A<A1, A2> (A1 a1, A2 a2)
implements
M<A1, A2>,
F<A1, A2>
{}
Ok, legal. Agora posso usar A
em qualquer lugar que eu usaria de outra forma M
ou F
.
Agora aqui está meu problema. Estou tentando fazer o seguinte, e falhando com erros do compilador.
public class DoublyNestedGenerics
{
interface M<K, V> {}
interface F<I, O> {}
record A <A1, A2> (A1 a1, A2 a2)
implements
M<A1, A2>,
F<A1, A2>
{}
private
static
<
D1,
D2,
D extends
M<D1, D2>
& F<D1, D2>
>
D
canItWork(final D1 d1, final D2 d2)
{
// return new A(d1, d2);
throw new UnsupportedOperationException();
}
}
Ok, então tudo compila. Mas se eu descomentar o retorno e substituir a exceção, recebo o seguinte erro de compilação.
DoublyNestedGenerics.java:28: warning: [rawtypes] found raw type: A
return new A(d1, d2);
^
missing type arguments for generic class A<A1,A2>
where A1,A2 are type-variables:
A1 extends Object declared in record A
A2 extends Object declared in record A
Ok, faz sentido. Deixe-me mudar o retorno para ser isso.
return new A<>(d1, d2);
Pressionar compilar me dá o seguinte erro do compilador.
DoublyNestedGenerics.java:28: error: incompatible types: cannot infer type arguments for A<>
return new A<>(d1, d2);
^
reason: no instance(s) of type variable(s) A1,A2 exist so that A<A1,A2> conforms to D
where A1,A2,D,D1,D2 are type-variables:
A1 extends Object declared in record A
A2 extends Object declared in record A
D extends M<D1,D2>,F<D1,D2> declared in method <D1,D2,D>canItWork(D1,D2)
D1 extends Object declared in method <D1,D2,D>canItWork(D1,D2)
D2 extends Object declared in method <D1,D2,D>canItWork(D1,D2)
1 error
Não entendi completamente o erro, então decidi simplificar o problema.
Eu alterei o método para usar alguns tipos hardcoded, em vez de apenas D1
and D2
. Aqui está a aparência do novo método.
private
static
<
D extends
M<Integer, Integer>
& F<Integer, Integer>
>
D
canItWorkAttempt2(final Integer d1, final Integer d2)
{
// return new A<>(d1, d2);
throw new UnsupportedOperationException();
}
Trocar os comentários e pressionar compilar me deu o seguinte erro do compilador.
DoublyNestedGenerics.java:44: error: incompatible types: cannot infer type arguments for A<>
return new A<>(d1, d2);
^
reason: no instance(s) of type variable(s) A1,A2 exist so that A<A1,A2> conforms to D
where A1,A2,D are type-variables:
A1 extends Object declared in record A
A2 extends Object declared in record A
D extends M<Integer,Integer>,F<Integer,Integer> declared in method <D>canItWorkAttempt2(Integer,Integer)
1 error
Ok, muito menor e, portanto, mais fácil de analisar.
Uma coisa que me chamou a atenção foi que dizia A1 extends Object declared in record A
.
Bem, isso não está certo -- deveria ser Integer
, não Object
. Talvez a inferência precise de ajuda. Então, alterei o retorno para ser isto.
return new A<Integer, Integer>(d1, d2);
O que resultou no seguinte erro do compilador.
DoublyNestedGenerics.java:44: error: incompatible types: A<Integer,Integer> cannot be converted to D
return new A<Integer, Integer>(d1, d2);
^
where D is a type-variable:
D extends M<Integer,Integer>,F<Integer,Integer> declared in method <D>canItWorkAttempt2(Integer,Integer)
1 error
Progresso! Agora comecei a ter suspeitas e, para confirmá-las, decidi simplificar significativamente meu problema. Criei a seguinte classe.
record N (Integer n1, Integer n2)
implements
M<Integer, Integer>,
F<Integer, Integer>
{}
Compilado sem problemas. Lindo, vamos tentar mudar o tipo de retorno para usar isto em vez disso. Aqui está o que eu mudei para o retorno.
return new N(d1, d2);
Com grandes esperanças, apertei o botão de compilar.
DoublyNestedGenerics.java:50: error: incompatible types: N cannot be converted to D
return new N(d1, d2);
^
where D is a type-variable:
D extends M<Integer,Integer>,F<Integer,Integer> declared in method <D>canItWorkAttempt2(Integer,Integer)
1 error
Muito decepcionante. Mas outra coisa me ocorreu. No erro, dizia where D is a type-variable: D extends M<Integer,Integer>,F<Integer,Integer>
.
Eles usaram a palavra extends . Por desespero, tentei adicionar os seguintes tipos.
interface C<C1, C2> extends M<C1, C2>, F<C1, C2> {}
record N2 (Integer n1, Integer n2) implements C<Integer, Integer> {}
E então, a partir daí, mudei meu retorno para dizer isso.
final C<Integer, Integer> blah = new N2(d1, d2);
return blah;
Então pressionei compilar.
DoublyNestedGenerics.java:55: error: incompatible types: C<Integer,Integer> cannot be converted to D
return blah;
^
where D is a type-variable:
D extends M<Integer,Integer>,F<Integer,Integer> declared in method <D>canItWorkAttempt2(Integer,Integer)
1 error
Neste ponto, estou irritado.
A mensagem de erro está de alguma forma me dizendo que C<Integer,Integer> cannot be converted to D
. E também está me dizendo que D is a type-variable
, especificamente que D extends M<Integer,Integer>,F<Integer,Integer>
QUE É EXATAMENTE O QUE C FAZ . E ainda assim, ainda não funciona?
O que me traz aqui. O que estou esquecendo? E, novamente, gostaria de ajuda para elaborar um título melhor, se alguém estiver disposto a fazer sugestões.
Por fim, aqui está o código completo, caso tenha sido mais difícil de acompanhar.
public class DoublyNestedGenerics
{
interface M<K, V> {}
interface F<I, O> {}
record A <A1, A2> (A1 a1, A2 a2)
implements
M<A1, A2>,
F<A1, A2>
{}
record N (Integer n1, Integer n2)
implements
M<Integer, Integer>,
F<Integer, Integer>
{}
interface C<C1, C2> extends M<C1, C2>, F<C1, C2> {}
record N2 (Integer n1, Integer n2) implements C<Integer, Integer> {}
private
static
<
D1,
D2,
D extends
M<D1, D2>
& F<D1, D2>
>
D
canItWork(final D1 d1, final D2 d2)
{
// return new A<>(d1, d2);
throw new UnsupportedOperationException();
}
private
static
<
D extends
M<Integer, Integer>
& F<Integer, Integer>
>
D
canItWorkAttempt2(final Integer d1, final Integer d2)
{
final C<Integer, Integer> blah = new N2(d1, d2);
return blah;
// return new N(d1, d2);
// throw new UnsupportedOperationException();
}
}