Java Generics - General Class Extension with Common Function

I have a simple program, for example:

package test; public class TestGenericsInheritance { public static void main(String[] args) {} public static abstract class A<Q>{ public void foo2(Q obj){} public abstract <T> void foo(T obj); } public static class C extends A<Object>{ @Override public <T> void foo(T obj) {} } public static class B extends A{ @Override public <T> void foo(T obj) {} } } 

As you can see, it does nothing. Compiling these program files on java 1.6 and 1.7 with the following error:

/D:/Projects/.../test/TestGenericsInheritance.java: [24,19] test.TestGenericsInheritance.B is not abstract and does not cancel the abstract method foo (java.lang.Object) in test.TestGenericsInheritance.A / D : / Projects /.../ test / TestGenericsInheritance.java: [27,25] collision name: foo (T) in test.TestGenericsInheritance.B and foo (T) in test.TestGenericsInheritance.A have the same erasure, but neither one overrides the other /D:/Projects/.../test/TestGenericsInheritance.java:[26,9] method does not override or implement a method from a supertype

Classes C and B are semantically identical, however, class B does not recognize the foo method as an implementation of A # foo. To make this code compatible, I have to implement the A # foo method in class B with the following signature:

 public void foo(Object obj) 

My question is why my program does not compile? The generic types Q and T are completely independent, so why can I implement the generic function A # foo only when I explicitly specify the generic type Q for the inherited class A?

thanks

+8
java generics
source share
1 answer

B extends the original type A Since you are using a raw type, all generic information is deleted, not just a type variable that you did not specify (see Section 4.6 of the Java Language Specifications ). This means that A has the void foo(Object obj) method, while A<SomeType> has the <T> void foo(T obj) method.

If you override a method, it must have the same signature (optional after deleting the erased type of the overridden method). Interestingly, the override method may have another more specific return type. The signatures of your two methods are different (you need to erase the styles in the override method), so your example does not compile.

Erasing the type of reason was implemented as it is, it is backward compatible. The idea was that the new code would only use generics, and only the old code would use raw types. So the goal was not to make the raw types the most convenient (because the new code shouldn't use them), but to make the raw types the most compatible.

Consider, for example, the ArrayList class, which was introduced in Java 2 (long before generics). He had a method public Object[] toArray(Object[] a) . Generalizations were introduced in Java, and the signature of this method can be changed to public <T> T[] toArray(T[] a) (where T not an element type) without difficulty: due to the method of erasing the type, it is implemented for old code, which used (or subclassed) an ArrayList , not an ArrayList<SomeType> method signature remains the same.

+6
source share

All Articles