Java 使用字符串输入解析自定义对象

Java 使用字符串输入解析自定义对象,java,parsing,reflection,overriding,Java,Parsing,Reflection,Overriding,我想解析有输入值的对象。对象有子类 我不想在解析字符串时创建实例。 但是我想重写“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 newObjec

我想解析有输入值的对象。对象有子类

我不想在解析字符串时创建实例。 但是我想重写“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);

有一种很好的方法可以做到这一点。

为了获得最大的灵活性,我将解析代码移出到一个单独的解析器类中。例如,以下代码是我自己在项目中使用的解析器类的简化实现:

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);
    }
}
或者使用lambda:
ParseUtil.registerStringParser(File.class,s->新文件)

调用方负责决定如何解析类以及何时注册/取消注册
IStringParser

通过将解析代码从类本身移开,以后只需注册不同的
IStringParser
或更改
ParseUtil
类的
parse
方法,就可以很容易地更改实现。例如,在我自己的项目中,我使用以下解析方法,该方法为众所周知的Java类提供了一些合理的默认值,并用于解析没有注册其他
IStringParser
的对象:

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;
}
publicstatice-parse(字符串s,类clazz)抛出ParseException{
如果(s==null | | s.length()==0 | | clazz==null){
抛出新的IllegalArgumentException();
}
IStringParser-stringParser=getStringParser(clazz);
if(stringParser!=null){
返回stringParser.parse;
}
if(Number.class.isAssignableFrom(clazz)){
//单数
试一试{
if(clazz==Integer.class){
返回clazz.cast(Integer.parseInt);
}
if(clazz==Long.class){
返回clazz.cast(Long.parseLong(s));
} 
if(clazz==Double.class){
返回clazz.cast(Double.parseDouble);
} 
if(clazz==Float.class){
返回clazz.cast(Float.parseFloat);
}
if(clazz==Short.class){
返回clazz.cast(Short.parseShort(s));
}
if(clazz==Byte.class){
返回clazz.cast(Byte.parseByte);
}
}捕获(数字格式){
抛出新的ParseException(clazz,e);
}
} 
if(clazz==String.class){
回炉炉型;
}
if(clazz==Character.class){
如果(s.长度()==1){
回击次数(s.charAt(0));
}否则{
抛出新的ParseException(“无法分析字符\”+s+“\”);
}
}
if(clazz==Boolean.class){
开关{
案例“真”:
返回clazz.cast(Boolean.TRUE);
案例“假”:
返回clazz.cast(Boolean.FALSE);
案例“1”:
返回clazz.cast(Boolean.TRUE);
案例“0”:
返回clazz.cast(Boolean.FALSE);
违约:
抛出新的ParseException(“无法解析布尔\”+s+“\”);
}
}
if(clazz==Class.Class){
试一试{
返回clazz.cast(Class.forName);
}catch(classnotfounde异常){
抛出新的ParseException(clazz,e);
}
}
if(Enum.class.isAssignableFrom(clazz)){
@SuppressWarnings({“rawtypes”})
c类=(类)clazz;
@抑制警告(“未选中”)
对象o=枚举值of(c,s);
回炉炉型(o);
}
E结果=空;
试一试{
//如果所有其他操作都失败,请使用Gson解析该类
result=getGSON().fromJson(s,clazz);
}捕获(JsonSyntaxException e){
抛出新的ParseException(clazz.e);
}
如果(结果==null){
抛出新的ParseException(clazz);
}
返回结果;
}

如果方法不是静态的,那么不创建实例就无法实现。你真正的问题是什么?为什么要这样做?@realpoint我想重写parse方法。但它应该是静态的。或者我应该使用构造函数。但是没有覆盖注释。我的问题是,我想有一个方法可以与反射一起使用,它可以将字符串解析到我的对象。但是,为什么你想用反射而不是只调用该方法呢?@realpoint我想用反射来做这件事,因为调用该方法的代码首先会发现该对象的类型,然后应该解析它。
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;
}