Keir Simmons
Keir Simmons

Reputation: 1684

Java Generics - Specifying upper bound on a class implementing an interface which itself specifies an upper bound

I have the following interface:

public interface ISort<T extends Comparable<T>> {
    public void sort(T[] array);
}

My understanding of this is that the the <T extends Comparable<T>> tells the compiler that within this class, there may be some generic types T, and they must be a Comparable<T> or be any class which implements Comparable<T>.

I then have the following class:

public class Sort<T extends Comparable<T>> implements ISort<T> {

    public void swap(T[] array, int i, int j) {
        T temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public void sort(T[] array) {
        java.util.Arrays.sort(array);
    }

}

Again, I have the <T extends Comparable<T>> telling the compiler that within this class I will be using the type T which must form an IS-A relationship with Comparable<T>. However, why must I only type implements ISort<T>, why do I not need to write implements ISort<T extends Comparable<T>>? In order to help me understand this could you explain what exactly these generics statements are inferring to the compiler?

Upvotes: 3

Views: 2006

Answers (3)

Raffaele
Raffaele

Reputation: 20885

In the class declaration you introduce a type parameter with an upper bound. When you use T[] as the type of the first parameter of the sort method, you are not declaring anything (the declaration happens at the beginning of the file): you are merely using a type variable. Please, note the different phrasing:

  • at the beginning of the file, you declare a type parameter
  • in the signature of sort, we use a type variable

Bounds on type parameters are only allowed at declaration site, and the declaration can happen in three places:

  1. class declaration
  2. constructor definition
  3. method definition

Here you a quick table:

// class
public static class Foo<T> {
    // constructor
    public <A> Foo() {}
    // method
    public <B> void doSomething() {}
    // Not really allowed
    // public void doSomethingElse(List<T extends Number> bar) {}
    // here we have a wildcard, so you can do this
    public void doSomethingElse(List<? super T> bar) {}
}

Upvotes: 0

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280148

The syntax for generic type usage is SomeType<SomeTypeArgument>.

In your case

class Sort<T extends Comparable<T>> implements ISort<T> {
        // ^ declares new type parameter             ^ uses it as a type argument 
        //                             

You declare a new type parameter T with bounds that match the expectations in the type parameter T declared in ISort. You can therefore use Sort#T as a type argument for ISort.

This would be similar to

class Sort implements ISort<Integer> {

The only difference is you don't declare a type parameter, you use an existing type.

Upvotes: 2

rgettman
rgettman

Reputation: 178313

There is a difference between specifying T with the class and using T in the extends or implements clause.

When specifying T with the class, you are declaring the type parameter T, but in the extends or implements clause, you are using a type parameter that is already declared.

public class Sort<T extends Comparable<T>>  // Declare T to be Comparable<T>
    implements ISort<T>                     // Use T

Using a type parameter in the extends or implements clause is no different than using the type parameter in the body of the class.

Upvotes: 3

Related Questions