Alex Rivera | Logout

Generic instance variable in non-generic class

Asked 2010-07-07T03:03:52.513
14

I'm trying to write a class that has a generic member variable but is not, itself, generic. Specifically, I want to say that I have an List of values of "some type that implements comparable to itself", so that I can call sort on that list... I hope that makes sense.

The end result of what I'm trying to do is to create a class such that I can create an instance of said class with an array of (any given type) and have it generate a string representation for that list. In the real code, I also pass in the class of the types I'm passing in:

String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);

Originally I didn't even want to pass in the class, I just wanted to pass in the values and have the code examine the resulting array to pick out the class of the values... but that was giving me troubles too.

The following is the code I have, but I can't come up with the right mojo to put for the variable type.

public class MyClass {
    // This doesn't work as T isn't defined
    final List<T extends Comparable<? super T>> values;

    public <T extends Comparable<? super T>> MyClass (T... values) {
        this.values = new ArrayList<T>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable<? super T>> List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}

error on variable declaration line:

Syntax error on token "extends", , expected

Any help would be very much appreciated.

Edit: updated code to use List instead of array, because I'm not sure it can be done with arrays.

@Mark: From everything I've read, I

Edit
Report

2 Answers

2

I believe the following will achieve what you want (stronger typing of Comparable). This will prevent people adding Comparable objects which are not from your interface to the list and allow multiple implementations.

public class test<T extends ComparableType> {


final List<T> values = new ArrayList<T>();
  public test (T... values) {
      for(T item : values) {
          this.values.add(item);
      }
  }

  public List<T> getSortedLst() {
      Collections.sort(this.values);
      return Collections.unmodifiableList(this.values);
  }
}

public interface ComparableType extends Comparable<ComparableType> {}

public class ConcreteComparableA implements ComparableType {
  @Override
  public int compareTo(ComparableType o) {
    return 0;
  }
}

public class ConcreteComparableB implements ComparableType {
  @Override
  public int compareTo(ComparableType o) {
    return 0;
  }
}

edit:

I know this may be obvious; but if you do not wish the class to be Generic this solution will also work with:

 public class test {
  final List<ComparableType> values = new ArrayList<ComparableType>();

  public test (ComparableType... values) {
      for(ComparableType item : values) {
          this.values.add(item);
      }
  }

  public List<ComparableType> getSortedLst() {
      Collections.sort(this.values);
      return Collections.unmodifiableList(this.values);
  }
}
answered 2010-07-07T04:12:28.447
0

the type constraint you want on the variable can't be expressed directly. you can introduce a new type to bridge the problem.

static class MyList<T extends Comparable<? super T>> extends ArrayList<T>{}

final MyList<?> values;

however, there is no point to be extremely type safe in a private piece of code. Generic is there to help you clarify your types, not to obfuscate them.

answered 2010-07-07T06:31:50.603

Your Answer