2

I have the following class declaration:

public class UserVariable<T extends Comparable<T>> implements Comparable<UserVariable<T>>
{
    private T myValue;

    public void setValue(T value)
    {
        myValue = value;
    }

    public T getValue()
    {
        return myValue;
    }

    public int compareTo(UserVariable<T> rhs)
    {
        return getValue().compareTo(rhs.getValue());

    }
}

If I did that correctly, what I wanted is: UserVariable can be compared to other UserVariables and it's generic and accepts a type T that can be compared to other Ts.

I am having trouble invoking setValue() and passing it an Integer:

UserVariable<Integer> newVar = new UserVariable<Integer>();
newVar.setValue(new Integer(20));

gives me the error "The method setValue(Comparable<Comparable<T>>) in the type UserVariable<Comparable<Comparable<T>>> is not applicable for the arguments (Integer)".

I don't understand why I'm getting this error. First, Integer does implement Comparable<Integer>. Second, why does Comparable appear twice, in a nested fashion (Comparable<Comparable<T>>) in the error message? Yes, UserVariable also implements Comparable but the error is referring to the type of the method parameter, which is of type T, which should just be a T extends Comparable<T>, right?

UPDATE:

I've realized the problem is connected with the fact that I am retrieving the object from a wildcard collection:

Map<String, UserVariable<?>> myVars = new HashMap<>();

UserVariable<Double> v1 = new UserVariable<>();
v1.setValue(3.0);

myVars.put("doubleVar", v1);

myVars.get("doubleVar").setValue(new Double(30));

Adding the above code will reproduce the compile error on the last line.

My apologies, I'm afraid the question scope has changed entirely with that latest info, because I am pulling an object from the map of type UserVariable<?> and trying to call setValue() on that.

skrilmps
  • 625
  • 2
  • 10
  • 29
  • 3
    You should use `>`, however seeing that `Integer` implments `Comparable` and not `Comparable` this is unlikely the source of your problem. – kajacx Feb 03 '17 at 21:00
  • 1
    `public setValue` should be `public void setValue`. otherwise, after implementing compareTo, I can call `setValue(new Integer(20))` without an error – Daniel Puiu Feb 03 '17 at 21:00
  • possible duplicates: http://stackoverflow.com/questions/5013947/create-a-compareto-to-a-generic-class-that-implements-comparable, http://stackoverflow.com/questions/21544716/implementing-comparable-with-a-generic-class – prompteus Feb 03 '17 at 21:02
  • setValue must be void , you wrote it like a constructor ... – Mohsen_Fatemi Feb 03 '17 at 21:05
  • `UserVariable` doesn't implement `CompareTo()`, `public setValue()` has no returned type. How this code can compile ? – davidxxx Feb 03 '17 at 21:05
  • Thanks for pointing that out. When I typed my question I left out the `void`. Oops, sorry. It does exist in my code. The error is still the same. – skrilmps Feb 03 '17 at 21:06
  • I will add the compareTo() function. I left it out because right now it just returns 0. But I'll add it for clarity. – skrilmps Feb 03 '17 at 21:07
  • what version of javac are you using? It compiles and runs for me fine after fixing the void and compareTo. Java 8 here. – Patrick Parker Feb 03 '17 at 21:08
  • I think all I needed was to cast the object to a `UserVariable` in the last line: `(UserVariable)(myVars.get("doubleVar")).setValue(new Double(30));` I get an unchecked cast warning, for good reason, but this is an issue with the wildcard in the Map and not an issue with the class declaration after all. – skrilmps Feb 03 '17 at 22:01

1 Answers1

1

There are two things that need changing:

  • public class UserVariable<T extends Comparable<T>> implements Comparable<UserVariable<T>>

    In class declaration, you are implementing Comparable<UserVariable<T>> where UserVariable itself again implements Comparable that's why you are getting Comparable<Comparable<T>> in the error message.

  • public setValue(T value)

    Don't know whether it's a typo but the method needs a return type, you can change it to public void setValue(T value)

Below is an example that works after making these changes:

public class UserVariable<T extends Comparable<T>> implements Comparable<T> {

    @Override
    public int compareTo(T o) {
        // TODO Auto-generated method stub
        return 0;
    }

    private T myValue;

    public void setValue(T value){
        myValue = value;
    }

    public static void main(String[] args) {
        UserVariable<Integer> newVar = new UserVariable<Integer>();
        newVar.setValue(new Integer(20));
    }
}

Update

If you want to compare two UserVariable objects the you just need to implement compareTo method and add return type to setter method, below should work:

public class UserVariable<T extends Comparable<T>> implements Comparable<UserVariable<T>> {
    private T myValue;

    public void setValue(T value) {
        myValue = value;
    }

    public T getValue() {
        return myValue;
    }

    public int compareTo(UserVariable<T> rhs) {
        return getValue().compareTo(rhs.getValue());

    }

    public static void main(String[] args) {
        UserVariable<Integer> newVar = new UserVariable<Integer>();
        newVar.setValue(new Integer(20));
    }
}
Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102