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:
Parsables
but it doesn't work because you can't make abstract static functions. 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.