Generics in return types of static methods do not seem to get along well with inheritance. Please take a look at the following code:
class ClassInfo<C> {
public ClassInfo(Class<C> clazz) {
this(clazz,null);
}
public ClassInfo(Class<C> clazz, ClassInfo<? super C> superClassInfo) {
}
}
class A {
public static ClassInfo<A> getClassInfo() {
return new ClassInfo<A>(A.class);
}
}
class B extends A {
// Error: The return type is incompatible with A.getClassInfo()
public static ClassInfo<B> getClassInfo() {
return new ClassInfo<B>(B.class, A.getClassInfo());
}
}
I tried to circumvent this by changing the return type for A.getClassInfo(), and now the error pops up at another location:
class ClassInfo<C> {
public ClassInfo(Class<C> clazz) {
this(clazz,null);
}
public ClassInfo(Class<C> clazz, ClassInfo<? super C> superClassInfo) {
}
}
class A {
public static ClassInfo<? extends A> getClassInfo() {
return new ClassInfo<A>(A.class);
}
}
class B extends A {
public static ClassInfo<? extends B> getClassInfo() {
// Error: The constructor ClassInfo<B>(Class<B>, ClassInfo<capture#1-of ? extends A>) is undefined
return new ClassInfo<B>(B.class, A.getClassInfo());
}
}
What is the reason for this strict checking on static methods? And how can I get along? Changing the method name seems awkward.
Static and non-static generic methods are allowed, as well as generic class constructors. The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type.
it is a method accessible from outside the class where it is defined (public), it is a static method (static), it does not return any result (return type is void), and.
You cannot inherit a generic type. // class Derived20 : T {}// NO!
Just like type declarations, method declarations can be generic—that is, parameterized by one or more type parameters.
The static method in B does not override the static method in A but hides it. The JLS 8.4.8.3 explicitly says that the return types must be substitutable or it won't compile:
If a method declaration d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be return-type-substitutable (§8.4.5) for d2, or a compile-time error occurs.
And substitutability is defined in JLS #8.4.5:
A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2, if and only if the following conditions hold:
- [...]
- If R1 is a reference type then:
- R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or
- R1 = |R2|
In your case: d1 is the method in B, R1 is ClassInfo<B>
, d2 the method in A and R2 is ClassInfo<A>
. And ClassInfo<B>
is not a subtype of ClassInfo<A>
.
However, ClassInfo<? extends B>
can be converted to ClassInfo<? extends A>
. You can observe that behaviour in:
void someMethod(){
ClassInfo<B> b1 = (ClassInfo<B>) get1(); //does not compile
ClassInfo<? extends B> b2 = (ClassInfo<? extends B>) get2(); //compiles
}
ClassInfo<A> get1() {
return null;
}
ClassInfo<? extends A> get2() {
return null;
}
You can't override a static method. So when you declare the same static method, you are creating a new method.
public static ClassInfo<B> getClassInfo() {
return new ClassInfo<B>(B.class, A.getClassInfo());
}
But, when you declare your method with changed return type, it is not a valid method hiding, neither an override. So, both the getClassInfo()
method of class A
and getClassInfo()
method of class B
, conflict each other. As the method of class A is also visible in class B.
So, in other words, class B
has same method, as it has inherited from class A
, with change in return type. And since return type of method is not considered a part of method signature. Hence the conflict.
So, you need to have exactly same return type. In which case, class B will ignore the inherited method, and use its own.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With