2015-01-04 30 views
2

我想解析具有输入值的对象。该对象具有子类。使用字符串输入解析自定义对象

我不想在解析字符串时创建实例。 但我想重写方法'分析'。

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

如果该方法不是静态的,有没有创建实例的情况下没有办法做到这一点。你的*真实*问题是什么?你为什么想这样做? – RealSkeptic

+0

@RealSkeptic我想覆盖解析方法。但它应该是静态的。或者我应该使用构造函数。但是,然后没有覆盖注释。 而我的问题是,我想有一个方法,可以使用反射解析字符串到我的对象。 – RoboDeBanco

+0

但是,为什么你想用反射来做这件事,而不仅仅是调用方法呢? – RealSkeptic

回答

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));

调用者有责任决定如何解析类以及何时IStringParser已注册/未注册。

通过将解析代码从类本身移开,以后很容易通过注册不同的IStringParser或更改ParseUtil类的parse方法来更改实现。例如,在我自己的项目中,我使用下面的解析方法,它提供了众所周知的Java类中的某些合理的默认值,并使用Gson解析对于没有其他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; 
}