Generics in inverse types of static methods and inheritance

The generic return types of static methods do not seem to fit well with inheritance. 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 work around this by changing the return type for A.getClassInfo (), and now the error appears elsewhere:

 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 test of static methods? And how can I get along? Changing a method name seems uncomfortable.

+6
source share
2 answers

The static method in B does not override the static method in A, but hides it. JLS 8.4.8.3 explicitly states that return types must be replaceable or will not compile:

If the declaration of method d1 with return type R1 overrides or hides the declaration of another method d2 with return type R2, then d1 must be replaced with the return type (ยง8.4.5) for d2 or a compile-time error occurs.

And substitution is defined in JLS # 8.4.5:

Declaring a method d1 with return type R1 is a return type-replaceable for another method d2 with return type R2, if and only if the following conditions are true:

  • [...]
  • 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 an unchecked conversion (ยง5.1.9) or
    • R1 = | R2 |

In your case: d1 is the method in B, R1 is the ClassInfo<B> , d2 is the method in and R2 is equal to ClassInfo<A> . And ClassInfo<B> not a subtype of ClassInfo<A> .

However, ClassInfo<? extends B> ClassInfo<? extends B> can be converted to ClassInfo<? extends A> ClassInfo<? extends A> . You can observe this behavior 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; } 
+5
source

You cannot override a static method. Therefore, when you declare the same static method, you create a new method.

 public static ClassInfo<B> getClassInfo() { return new ClassInfo<B>(B.class, A.getClassInfo()); } 

But, when you declare your method with a modified return type, it is not a valid method that hides not to override . Thus, the getClassInfo() method of class A and getClassInfo() class B contradict each other. Since the class A method is also displayed in class B.

So, in other words, class B has the same method as inherited from class A , with a change in return type. And since the type of the returned method is not considered part of the method signature. Hence the conflict.

So you should have exactly the same type of return. In this case, class B will ignore the inherited method and use it.

+4
source

All Articles