简体   繁体   中英

Java - Generic List of Generic Abstract Classes

I am using a library that contains an abstract generic Parsable class:

public abstract class Parsable<T> {
  T parse(String s);
}

By subclassing this class allows users to create instances of types from Strings. I find myself having to parse lists of objects. For instance there could exist a IntParser extends Parsable<Integer> and I want to implement an IntListParser extends Parsable<List<Integer>> . This can be done pretty straightforwardly:

public class IntListParser extends Parsable<List<Integer>> {
  List<Integer> parse(String s) {
    IntParser ip = new IntParser();
    String[] strings = s.split(",");
    List<Integer> result;
    for (String s : strings) {
      result.add(ip.parse(s));
    }
    return result;
  }
}

This can be done successfully for every type of parser. There is nothing special about an Integer in this example. After writing several of these identical classes I decided it was time to create a generic to do this:

public class GenericListParser<TParser extends Parsable<T>> extends Parsable<List<T>> {
  List<T> parse(String s) {
    TParser tp = new TParser();
    String[] strings = s.split(",");
    List<T> result;
    for (String s : strings) {
      result.add(tp.parse(s));
    }
    return result;
  }
}

Unfortunately this doesn't work because the command new TParser() doesn't compile. Is there any way to get around this or am I forced to create a new copy of this code for every type of Parser?

The solutions that I tried that didn't work are:

  • Making parse static. This would prevent having to create instances of the Parsables but it doesn't work because you can't make abstract static functions.
  • Have GenericListParser<TParser extends Parsable<T>> extend Parsable<T> instead of Parsable<List<T>> . This would allow its parse function to call Parsable<T> 's parse function because it is its own super. This doesn't work because the return type of parse is T and you can't cast List<T> to T .

Rather than trying to create a parser for something unknown, accept it as a parameter:

public class GenericListParser<TParser extends Parsable<T>> extends Parsable<List<T>> {
  private TParser tp = null;
  public GenericListParser(TParser parser) {
      this.tp = parser;
  }
  List<T> parse(String s) {
    String[] strings = s.split(",");
    List<T> result;
    for (String s : strings) {
      result.add(tp.parse(s));
    }
    return result;
  }
}

I think your approach is not the right way and that you should delete all your list parsing classes and replace them, and your new "generic" class, with a single typed static utility method:

public ststic <T> List<T> parseList(String s, Parsable<T> p) {
    List<T> result = new ArrayList<>();
    for (String s : s.split(","))
        result.add(p.parse(s));
    return result;
}

Now you can call it like this:

List<Integer> ints = parseList("1,2,3", new IntParser());

If you need separate classes for each list parser, then:

public abstract class ListParser<T> extends Parsable<List<T>> {
    private final Parsable<T> Parsable;
    protected ListParser(Parsable<T> p) {
        parsable = p;
    }
    public List<T> parse(String s) {
        List<T> result = new ArrayList<>();
        for (String s : s.split(","))
            result.add(parsable.parse(s));
        return result;
    }
}

Then to use:

public class IntListParser extends ListParser<Integer> {
    public IntListParser() {
        super(new IntParser());
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM