interface IA{}
interface IB{}
class A{}
abstract class C extends A implements IA {}
abstract class D extends C implements IB {}
class E extends D implements IA, IB {}
class B <T extends A & IA> {}
class Test {
B<? extends IB> t = new B<E>();
}
First, I’m going to convert your question into Kotlin:
interface IA
interface IB
open class A
abstract class C : A(), IA
abstract class D : C(), IB
open class E : D(), IA, IB
class B<T> where T : A, T : IA
class Test {
fun foo(): B<out IB> = B<E>()
// ERROR ^^^^^^
}
Now, let’s examine the error message on out IB:
Type argument is not within bounds.
Expected: A
Found: IB
Type argument is not within bounds.
Expected: IA
Found: IB
The problem is that this parameter is required to implement both A and IA, which is what you specified in the where clause (intersection type). But IB implements neither. If you say out E it’s fine and does not require the explicit cast to E:
val t: B<out E> = B()
This was an interesting brain teaser that got me to learn about the where keyword - I didn’t even know that Kotlin had intersection types!
I want to add variance. because Test.t will set B with a type that doesn’t extend both C and D, extends another subtype of A, and implements IA and IB.
Now, In my code, we write subtype of B and add variance with where. But I think it is not good to read. So I want to know why to couldn’t add variance like Java or how to pass this problem.
interface IA{}
interface IB{}
class B <T extends IA> {}
class Test {
B<? extends IB> t = new B<>();
}
I’m still missing something between these two lines:
class B <T extends IA> {}
B<? extends IB>
The first line says that the generic type parameter to class B must extend/implement/be an IA. The second line arbitrarily redefines what types a B class can take says that B’s type parameter will be from a totally unrelated interface IB.
This looks like a contradiction to me. I understand that you can “make it work out” with an E class implementing IA and IB, but that doesn’t remove the contradiction. I think due to type erasure that if it compiles, it will run fine. It still seems to me you may have found a bug in Java generics.