kesarling
kesarling

Reputation: 2260

How to compare two different generic instantiations of a class in Java?

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?

Upvotes: -2

Views: 94

Answers (2)

WJS
WJS

Reputation: 40047

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.

Upvotes: 2

babanin
babanin

Reputation: 3584

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);

Upvotes: 3

Related Questions