Search code examples
javagenericsmethodsinterfacegeneric-method

Bounding type parameters of generic methods with interfaces?


So I have 2 versions of the same method.

Version 1:

public static <T> int countGreaterThan(T[] anArray, T elem) 
    {
        int count = 0; 
        for (T e : anArray)
        {
            if (e > elem)
                count++;
        }
        return count;
    }

Version 2:

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem)
    {
        int count = 0;
        for (T e : anArray)
        {
            if (e.compareTo(elem) > 0)
                count++;
        }
        return count;
    }

Eclipse complains about Version 1 because the > operator can only be used when comparing primitives, which makes sense to me.

So to fix this problem, the internet tells me to use a type parameter bounded by the Comparable interface. This is where I start to lose grasp of what's going on...

From my basic understanding of interfaces, a class that implements an interface must provide a method body for each of the methods declared in the interface.

Thus, why doesn't Version 2 have to look like this?

public int compareTo(T o)
    {
        //stuff for method body
    }


    public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem)
    {
        int count = 0;
        for (T e : anArray)
        {
            if (e.compareTo(elem) > 0)
                count++;
        }
        return count;
    }

^I get that this isn't correct syntax, but I just did it to illustrate my question as to why I don't have to write a method body for the method in the Comparable interface in this situation.

Please try to keep the explanation in Layman's terms. I've been teaching myself this stuff, so simple explanations help me understand the more technical side of topics when I research them further.


Sorry for the confusion, let me clarify.

Here is the code for the Comparable interface:

public interface Comparable<T> {
   public int compareTo(T o);
     }

There is no method body for compareTo() because it's an interface. Why don't I have to manually write a body for compareTO() so I can use the interface in my countGreaterThan() method?

Is it because the interface is part of the Java Collections Framework (if that's why please explain how that works)

Here's a different situation where I create my own interface:

public interface Dance { //an interface
  public void boogie(int count);
}

and in order to implement that interface in different classes I need to write method bodies in those classes for the method in the dance interface.

public class theMoonwalk implements Dance {
  public void boogie(int count) {
    System.out.println("Slide " + count + " times!");
  }
  public void mJ() {
    System.out.println("Michael Jackson did this dance!");

}
public class theHustle implements Dance {
  public void boogie(int steps) {
    System.out.println("Step " + steps + " times!");
  }
}
public class theJitterBug implements Dance {
  public void boogie(int twists) {
    System.out.println("Twist " + twists + " times!");
  }
}

Why don't I have to write a method body for compareTo() (because a method body is not included in the Comparable interface for compareTo() )?


Solution

  • The type that T ultimately refers to has to implement Comparable<T>, not the class that you're declaring the type bound on.

    To make it a bit simpler: in order to use your countGreaterThan method, whatever objects are contained in your array and in your elem argument must be a Comparable object.

    This means that an invocation like this is acceptable:

    Integer[] foo = {1, 2, 3, 4, 5};
    YourClass.countGreaterThan(foo, 2);
    

    Your type is bound to Integer, and Integer implements Comparable<Integer>.

    This is not acceptable:

    Object[] bar = {new Object(), new Object(), new Object()};
    YourClass.countGreaterThan(bar, new Object());
    

    Your type is bound to Object, and Object does not implement Comparable. The same logic applies to a custom object that you implement; if it isn't bound to Comparable, then it's not going to be in the proper bound.