我想解析具有输入值的对象。该对象具有子类。
当我想解析字符串时,我不想创建实例。 但我想覆盖方法'parse'。
class A {
public A(object param) {
//code
}
public A parse(String input) {
//code
}
}
class B extends A {
public B parse(String input) {
//code
}
}
当我解析我想要的对象时,用反射来做:
A newObject = Class.forName(className).getMethod("parse", myParseText);
有没有一种很好的方法可以做到这一点。
答案 0 :(得分:0)
为了获得最大的灵活性,我将解析代码移到单独的解析器类中。以下代码是我自己在项目中使用的解析器类的简化实现:
public final class ParseUtil {
public interface IStringParser<E> {
public E parse(String s) throws ParseException;
}
private ParseUtil() {}
private static Map<Class<?>, IStringParser<?>> STRING_PARSERS = new ConcurrentHashMap<>();
public static <E> void registerStringParser(Class<E> c, IStringParser<E> p){
STRING_PARSERS.put(c, p);
}
@SuppressWarnings("unchecked")
public static <E> IStringParser<E> getStringParser(Class<E> c){
return (IStringParser<E>) STRING_PARSERS.get(c);
}
public static <E> E parse(String s, Class<E> clazz) throws ParseException{
if (s == null || s.length() == 0 || clazz == null) {
throw new IllegalArgumentException();
}
IStringParser<E> stringParser = getStringParser(clazz);
if (stringParser == null) {
throw new ParseException(clazz);
}
return stringParser.parse(s);
}
}
然后可以将IStringParser
任意类的ParserUtil
实现注册到ParseUtil.registerStringParser(File.class, new IStringParser<File>() {
@Override
public File parse(String s)throws ParseException {
return new File(s);
}
});
,如下所示:
ParseUtil.registerStringParser(File.class, s -> new File(s));
或使用lambda:IStringParser
调用者有责任决定如何解析一个类以及IStringParser
何时注册/未注册。
通过将解析代码从类本身移开,以后只需注册不同的parse
或更改ParseUtil
类的IStringParser
方法,就可以轻松更改实现。例如,在我自己的项目中,我使用以下parse方法为已知的Java类提供一些合理的默认值,并使用Gson来解析没有注册其他public static <E> E parse(String s, Class<E> clazz) throws ParseException{
if (s == null || s.length() == 0 || clazz == null) {
throw new IllegalArgumentException();
}
IStringParser<E> stringParser = getStringParser(clazz);
if (stringParser != null) {
return stringParser.parse(s);
}
if (Number.class.isAssignableFrom(clazz)) {
// simple number
try {
if (clazz == Integer.class) {
return clazz.cast(Integer.parseInt(s));
}
if (clazz == Long.class) {
return clazz.cast(Long.parseLong(s));
}
if (clazz == Double.class) {
return clazz.cast(Double.parseDouble(s));
}
if (clazz == Float.class) {
return clazz.cast(Float.parseFloat(s));
}
if (clazz == Short.class) {
return clazz.cast(Short.parseShort(s));
}
if (clazz == Byte.class) {
return clazz.cast(Byte.parseByte(s));
}
} catch (NumberFormatException e) {
throw new ParseException(clazz, e);
}
}
if (clazz == String.class) {
return clazz.cast(s);
}
if (clazz == Character.class) {
if (s.length() == 1) {
return clazz.cast(s.charAt(0));
} else{
throw new ParseException("Unable to parse Character \"" + s + "\"");
}
}
if (clazz == Boolean.class) {
switch (s) {
case "true":
return clazz.cast(Boolean.TRUE);
case "false":
return clazz.cast(Boolean.FALSE);
case "1":
return clazz.cast(Boolean.TRUE);
case "0":
return clazz.cast(Boolean.FALSE);
default:
throw new ParseException("Unable to parse boolean \"" + s + "\"");
}
}
if (clazz == Class.class) {
try {
return clazz.cast(Class.forName(s));
} catch (ClassNotFoundException e) {
throw new ParseException(clazz, e);
}
}
if (Enum.class.isAssignableFrom(clazz)) {
@SuppressWarnings({ "rawtypes" })
Class c = (Class)clazz;
@SuppressWarnings("unchecked")
Object o = Enum.valueOf(c, s);
return clazz.cast(o);
}
E result = null;
try {
// if all else fails use Gson to parse the class
result = getGSON().fromJson(s, clazz);
} catch (JsonSyntaxException e) {
throw new ParseException(clazz. e);
}
if (result == null) {
throw new ParseException(clazz);
}
return result;
}
的对象:
{{1}}