开发者

Converting a string value to an unkown (at compile time) object type

I have a class type and I have a value in a string:

Class<?> type = Integer.class // <-- in reality, that type is 
                              // determined at runtime
String value = "3";           // <-- same here, actually read from a file

My goal is to instantiate an instance of 'type' and fill it with the value of 'value'... So that I have the equivalent of

Integer i = new Integer(value);

Is the only possible way to do that a long chain of if-statements:

if (type == Integer.class) {
  // do this
}开发者_Go百科

Or is there another clever/right way to do that? The possible class types could be totally different like Integer/Date etc...

Edit1

Here some more context:

I have a file with a number of values which a textual representations of instances of different datatypes:

1|3.4|2011-08-24

In my program, I get a class type and a method in that class which are both unknown to me at compile time.

I want to call that method on an instance of that type, with the values from the file as parameters. But for that I do have to have the corresponding object to that values, in the example that could be an Integer/int, a float/double, a Date. I can get these datatypes for the formal parameters of the method via reflection, but I'm uncertain about the best way to proceed with the conversion from string to the object...

Maybe this pseudo program will clear things up:

String[] values = getValuesFromFile;
Class<?> type = getType();
Method method = getMethod();
Class<?>[] formalParameterTypes = getMethodParameterTypes();
Object[] objects;
for(int i; i < values.length; i++)
  objects[i] = convert(values[i],formalParameterTypes[i]);
method.invoke(objects);


Dynamic class loading and reflection were invented to solve such problems. E.g.

Class<?> type = Class.forName("MyClassName");
Object obj = type.newInstance();

Now if you want to set fields in the object, you have two options:

  • if the potential classes share a common base class/interface, you can cast the object down to that interface and manipulate it via the interface methods,
  • if the potential classes aren't related by inheritance but have the same method/field, you can set the field value through bean introspection, or you can call the method using reflection.


To my understanding, you want something like this:

Object instance = createMagically(getClass(), getString());

where getClass() might return Integer.class and getString() the value "42". But the value pair Date.class and "15 Apr 2011" is expected too.

At one point you'll have to work with conditions (if/else if) because, in general, every type has it's own conversion rules. There is no universal constructor to create an instance from a String.

So you could implement a "factory" method like this:

public static Object createInstance(Class<?> type, String content) {
  if (type.equals(Integer.class)) return new Integer(content);
  else if // ...
  return content;  // just an idea for a default if the type can't be handled
}

And then again, to use the return value, you may need some more if/else if to determine the actual type (if (value instancof Integer) ...)

So, from my point of view - you have to do a lot of checks, but you can hide the ugly magic in utility classes.


If your type is limited to the wrapper classes for the primitive data types, all classes have a static valueOf(String) method, which can be used to parse a String and return a valid instance.

I would use reflection to find and invoke the method and use the result:

public static void main(String[] args) throws Exception {
    int i = parse(Integer.class, "4711");
    double d = parse(Double.class, "47.11");
    boolean b = parse(Boolean.class, "true");
    System.out.println(i);
    System.out.println(d);
    System.out.println(b);
}

public static <T> T parse(Class<T> type, String value) {
    try {
        return (T)type.getDeclaredMethod("valueOf", String.class).invoke(null, value);
    }
    catch(Exception e) {
        throw new RuntimeException(e);
    }
}


Using JSON you can convert string to object at runtime, without knowing the original type at the beginning.


If values have only string representations, you would to do so:

String typeName = ...
String value = ...
Class<?> type = Class.forName(typeName);
Constructor<?> constructor = type.getConstructor(String.class);
Object instance = constructor.newInstance(value);
// cast the instance to actual class
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜