tags:

views:

80

answers:

4
interface Addable<E> {
    public E add(E x);
    public E sub(E y);
    public E zero();
}

class SumSet<E extends Addable> implements Set<E> {

    private E element;

    public SumSet(E element) {
        this.element = element;
    }

    public E getSum() {
        return element.add(element.zero());
    }
}

It seems that element.add() doesn't return an E extends Addable but rather an Object. Why is that? Has it anything to do with Java not knowing at run-time what the object types really are, so it just assumes them to be Objects(thus requiring a cast)?

Thanks

+5  A: 

It should be:

class SumSet<E extends Addable<E>> implements Set<E> {

Your original code specifies that each element of SumSet must be an instance of E, a class that implements Addable (which is equivalent to Addable<Object>). By changing Addable to Addable<E>, you're specifying that add, sub, and zero methods of the E class must accept and return instances of E (rather than just Object).

Note that the E type variable in SumSet has nothing to do with the above E variable. So:

class SumSet<T extends Addable<T>> implements Set<T> {

    private T element;

    public SumSet(T element) {
        this.element = element;
    }

    public T getSum() {
        return element.add(element.zero());
    }
}

works fine too.

Matthew Flaschen
Yes, that does, indeed, work as expected. Thanks!
devoured elysium
+9  A: 

Try:

class SumSet<E extends Addable<E>> implements Set<E> {

I don't know if this is exactly what you mean but basically the problem is that you're using Addable in the declaration of SumSet as a raw type. That strips off all generic parameter types and makes Addable appear to SumSet as:

interface Addable {
  Object add(Object x);
  Object sub(Object y);
  Object zero();
}

Obviously Object is not an E, hence the error. See What is the raw type? from the Java Generics FAQ.

On a side note public is unnecessary on methods in interface definitions.

cletus
Type erasure strikes again! @devoured: Java has no idea what generics are at runtime, so it just ignores them then. This occasionally results in fun bugs like this one.
ehdv
On a side note `public` is unnecessary on methods in **public** interface definitions.
Willi
+3  A: 

You need to say <E extends Addable<E>>, not <E extends Addable>.

This is because when using a raw type, all references to its (non-existent) type parameters get erased.

Chris Jester-Young
A: 

Rather than creating a SumSet class that implements Set, you might want to consider whether you can get what you need by writing a method that can sum all of the elements in the set.

public static <T extends Addable<T> > T sum(Set<T> set)
{
    T sum = null;
    for (T t : set)
    {
        if (sum == null)
        {
            sum = t;
        }
        else
        {
            sum = sum.add(t);
        }
    }
    return sum;
}
Matthew T. Staebler