views:

1146

answers:

3

I am extending a class defined in a library which I cannot change:

public class Parent
{
    public void init(Map properties) { ... }
}

If I am defining a class 'Child' that extends Parent and I am using Java 6 with generics, what is the best way to override the init method without getting unchecked warnings?

public class Child extends Parent
{
    // warning: Map is a raw type. References to generic type Map<K,V> should be parameterized
    public void init(Map properties) { }
}

If I add generic parameters, I get:

   // error: The method init(Map<Object,Object>) of type Child has the same erasure as init(Map) of type Parent but does not override it
   public void init(Map<Object,Object>) { ... }
   // same error
   public void init(Map<? extends Object,? extends Object>) { ... }
   // same error
   public void init(Map<?,?>) { ... }

This error occurs regardless of whether I use a specific type, a bounded wildcard, or an unbounded wildcard. Is there a correct or idiomatic way to override a non-generic method without warnings, and without using @SuppressWarnings("unchecked")?

+1  A: 

Short answer: no way to do that.

Unsatisfying answer: disable the (specific) warnings in your IDE/build.xml.

If you cannot change the library, alas, you have to stick with non-generic methods.

The problem is that, despite after type erasure both init() have the same signature, they may in fact be different methods -- or the same(*). Compiler cannot tell should it do override or overload, so it's prohibited.

(*) Suppose the library developer meant init(Map<String,Integer>). Now you are implementing init(Map<String,String>). This is overloading, and two methods should exist in the vtable of Child class.

But what if the library developer meant init(Map<String,String>)? Then it's overriding, and your method should replace original init in Child class, and there would be only one method in the vtable of Child.

P.S. I hate how Generics implemented in Java :-(

Vladimir Dyuzhev
+5  A: 

Yes, you have to declare the overriding method with the same signature as in the parent class, without adding any generics info.

I think your best bet is to add the @SuppressWarnings("unchecked") annotation to the raw-type parameter, not the method, so you won't squelch other generics warnings you might have in your own code.

Dov Wasserman
@SuppressWarnings is definitely your best bet here. Sucks, but that's what happens when you try to force generics into a library that doesn't use them.
Kevin Day
A: 

You have to declare the method with the same signature as the parent, and therefore you will get warnings when you compile. You can suppress them with @SuppressWarnings("unchecked")

The reason why there is no way to get rid of this is that the warnings are there to let you know that it's possible to create Collections with invalid types in them. The warnings should only go away when all code that might allow that has been removed. Since you are inheriting from a non-generic class it will always be possible to create a Collection with invalid contents.

DJClayworth