-2

MRE because well, assignment... sigh

This is the problem I'm stuck on:
Consider the following class:

class MyClass<T extends Comparable<T>> implements Comparable<MyClass<T>> {

... override the compareTo
}

This allows me to compare MyClass<Integer> with another MyClass<Integer> or even MyClass<MyClass<Integer>> with another MyClass<MyClass<Integer>>. However, the assignment requires me to be able to compare MyClass<MyClass<Integer>> with MyClass<MyClass<String>> as the comparison just uses a counter and returns whichever class has the bigger counter as the greater of the two.
How would I go about achieving this? My guess is that the Comparator comes into play as is apparent here. However, I'm not able to quite put my finger on it. Is it as simple as just using the compare(Object,Object) from the Comparator or is it something else?

1
  • 1
    There might be information in the original assignment which might make it more clear what you are trying to do or what you are supposed to do. That's why the original assignment should be in the question. Commented Oct 8, 2023 at 21:31

2 Answers 2

3

You can use ? knowns as wildcard instead of specifying the type explicitly:

class MyClass<T extends Comparable<T>> implements Comparable<MyClass<?>> {
    private int counter; // or any other variable
    
    @Override
    public int compareTo(MyClass<?> o) {
        return counter - o.counter;
    }
}

And then use it like:

MyClass<String> string = new MyClass<>();
MyClass<Integer> integer = new MyClass<>();

int result = string.compareTo(integer);
Sign up to request clarification or add additional context in comments.

4 Comments

This will also work for raw instantiations, right?
@kesarlingHe-Him - Right
@kesarlingHe-Him Raw types erase all generics in scope. So even if you had implements Comparable<MyClass<T>> it would "work" for the raw type MyClass. But that doesn't really matter, because you should never use raw types unless you literally cannot avoid it (e.g., interacting with very old legacy code).
Note it doesn't make much sense to bound T with extends Comparable<T>, unless it being comparable is important for some other reason. Because right now, the T is not used by the compareTo implementation, nor would it be possible for it to be, because T could not be compared with ?.
2

Based on Babanin's answer I have a few suggestions.

  • get rid of the T extends Comparable<T> as it doesn't come into play.
  • although it may not matter in this case, don't get into the habit of subtracting ints for comparisons. Using Integer.compare(int a, int b) will ensure that you won't get wrong results when you encounter int overflow.
class MyClass<T> implements Comparable<MyClass<?>> {
    T value;
    int counter;
    public MyClass(T val, int v) {
        this.counter = v;
        this.value = val;
    }
    
    @Override
    public int compareTo(MyClass<?> ob) {
        return Integer.compare(this.counter, ob.counter);
    }
}

And an alternative is to declare an abstract class which has the supporting counter methods and values. Then it just a matter of extending it. Of course, depending on your use case, this alternative may not be useful (and it does use up your single allowable class extension).

abstract class MyCounter implements Comparable<MyCounter> {
    protected int counter;
    public int getCounter() {
        return counter;
    }
    public int compareTo(MyCounter obj) {
        return Integer.compare(this.counter, obj.counter);
    }
    // other methods that may be useful to a counter.
}     

class MyClass<T> extends MyCounter {
    T value;
    public MyClass(T val, int v) {
        this.counter = v;
        this.value = val;
    }
    // other required code here.
} 

And consider that MyClass<T> can't support operations that would be unique to type T. For example, you can't have both a divide method and a reverseString method even though T could be Double or String.1 But you can have a List<T> getList() method and a void addToList(T val) method since lists may hold different types.


1 For limited types you can do this but you have to check the types, make certain the operation fits that type, and then cast to that type. But this would be a poorly designed class and simply does not scale.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.