views:

308

answers:

3

Hello.

I've made an example to demonstrate my problem:

Metrical.java

public interface Metrical<T>
{
    double distance(T other);
}

Widget.java

public class Widget implements Metrical<Widget>
{
    private final double value;

    public Widget(double value) { this.value = value; }

    public double getValue() { return value; }

    public double distance(Widget other) { return Math.abs(getValue() - other.getValue()); }
}

Pair.java

public class Pair<T>
{
    private final double value;
    private final T object1, object2;

    public Pair(T object1, T object2, double value)
    {
     this.object1 = object1;
     this.object2 = object2;
     this.value = value;
    }

    public T getObject1() { return object1; }

    public T getObject2() { return object2; }

    public double getValue() { return value; }
}

Algorithm.java

import java.util.Set;

public class Algorithm<T extends Metrical<T>>
{
    public void compute(Set<T> objects)
    {

    }

    public void compute(Set<Pair<T>> pairs)
    {

    }
}

So, in Algorithm.java, Set< Pair< T >> is being seen as a Set< T > and thus I am having type erasure problems. However, is there any way I can get away with something like this without naming the methods differently? Both variants of the algorithm are meant to operate on T's, but I need to allow for different arguments. They compute the same thing, so in an effort to avoid confusion, I would rather not name them differently. Is there any way to accommodate this?

+3  A: 

No there isn't.

You have to remember that someone could call your method with just a vanilla Set, in which case which one would be called?

That's why you can't do it. Just like you can't do:

interface A {
  void blah(Set set);
  void blah(Set<T> set);
}

Same problem.

The type information isn't available at runtime (ie type erasure).

cletus
+2  A: 

Sorry, the bad news is that you cannot do this:

public class Algorithm<T extends Metrical<T>> {
    public void compute(Set<T> objects) {
    }

    public void compute(Set<Pair<T>> pairs) {
    }
}

Due to erasure, both will erase to the same signature. There is no way around this short of renaming one of the methods.

Eddie
Renaming one of the methods might not be a bad idea anyway - since they'll both be doing (slightly) different things (I guess).
harto
+2  A: 

Sadly, this is the major area where Java Generics falls down... there is just no good solution.

I've generally resorted to making a new class, with the interface as Set<Pair<T>>, but that wraps Set<Pair<T>> (without extending it, which would cause the same problem).

Chris Arguin