0

I have classes that are structured like the ones below:

interface Z {}

interface Y extends Z {}

interface X extends Y {}


private static class A<T extends Z> {}

private static class B<T extends Y> extends A<T> {}

private static class C extends B<X> {}

Why is the first one valid while the second one is not?

private Class<? extends A<? extends Z>> clazz = C.class; // valid
private Class<? extends A<? extends Z>> clazzb = B.class; // error: Type mismatch: cannot convert from Class<TEST.B> to Class<? extends TEST.A<? extends TEST.Z>>

I guess it is because the type of Y is unclear in the second example but how would you be able to clarify it?

Thank you

Gerrit Sedlaczek
  • 1,231
  • 1
  • 14
  • 32
  • May be because `B` is generics where `T` is undefined and in `C` type of B is defined as `X` since you extend `B` – Eklavya May 14 '20 at 12:20
  • 1
    Does this answer your question? [Java: how do I get a class literal from a generic type?](https://stackoverflow.com/questions/2390662/java-how-do-i-get-a-class-literal-from-a-generic-type) – Oleg May 14 '20 at 12:30
  • 1
    @Eklavya Yes I guess so. While `T` in `B` is not defined it has to be at least `Y` and therefore should qualify as `Z`. – Gerrit Sedlaczek May 14 '20 at 12:30

1 Answers1

0

Java Class literal constraint

Simply said; no you can't bound the Class literal assignment as B<T> is a generic type, i.e. you can have:

Class<? extends A<? extends Z>> clazzb = B<X>.class; // illegal statement
// OR
Class<? extends A<? extends Z>> clazzb = B<W>.class; // assuming W is a sub-type of X

as there is only one class literal (in terms of byte code (runtime) and in terms of language constraints (compile-time)): B.class

And since the compiler won't be able to know of which type the type parameter T would be for the B class, it won't allow such an assignment.

Legal assignment

Below assignment statement would be legal (compiles fine):

Class<? extends A> clazzb = B.class;

but with warnings and that would perfectly complies with the Generic Class and Type Parameters Java Language Specification.

I've seen many times a Java specific-pattern where developers work-around the compiler type-check with a generic utility method inferring its return type to match the assigned reference type:

<!-- language : lang-java -->

@SuppressWarnings("unchecked")
public static <T> Class<T> inferType(Class<?> clazz) {
    return (Class<T>) clazz;
}

Then you would be able to perform what used to be forbidden:

Class<? extends A<? extends Z>> clazzb = generify(B.class);

Note that this should be nothing but a non-recommended workaround. Just to let you be more sure, here down a quite confusing statement that compiles just fine:

Class<C> clazzb = generify(A.class);

At first glance, that should not work, but it will as you are assigning a class literal to a class reference after all.

tmarwen
  • 15,750
  • 5
  • 43
  • 62