在Java中通过反射强制转换对象



我正在编写一个反序列化器方法,它看起来像这样:

public <T> T deserialize(Object[] result, String[] fields, Class<T> type);

所以基本上我将传入一个结果数据数组,它是所有对象,以及一个类类型T,我需要将数组中的数据转换为给定类中的类型,并创建一个T类型的新类并返回它。String[]字段为Object[]结果中数据对应的字段名。字段名将与类T对应。

强制转换需要使用给定类的反射来找出每个字段的类型。

result = ["Mike", "London", 28];
fields = ["name", "location", "age" ];

分类T =

public class GivenClass{
  private String name;
  private String location;
  private Integer age;
  public GivenClass(String name, String location, Integer age){
    this.name = name;
    this.location = location;
    this.age = age;
  }
}

类实现

static class GivenClass {
    private String name;
    private String location;
    private Integer age;
    public GivenClass(String name, String location, Integer age) {
        this.name = name;
        this.location = location;
        this.age = age;
    }
    public GivenClass(Map<String, Object> data) throws Exception {
        for (Field f : GivenClass.class.getDeclaredFields())
            f.set(this, data.get(f.getName()));
    }
    public Map<String, Object> serialize() throws Exception {
        Map<String, Object> fields = new HashMap<String, Object>();
        for (Field f : GivenClass.class.getDeclaredFields()) 
            fields.put(f.getName(), f.get(this));
        return fields;
    }
    @Override
    public String toString() {
        return "age=" + age + ", location=" + location + ", name=" + name;
    }
}

例子:

public static void main(String[] args) throws Exception {
    GivenClass o1 = new GivenClass("Mike", "London", 28);
    Map<String, Object> serialized = o1.serialize();
    GivenClass o2 = new GivenClass(serialized);
    System.out.println(o2.toString());
}
输出:

age=28, location=London, name=Mike

您需要自己进行转换。反射不会转换(它只会检查对象的类型是否正确)

反射不会给你方法/构造函数参数的名字。(你可以从调试字节码中获得它们,但这是一个真正的痛苦)

我采用的方法是使用构造函数参数与字段顺序相同的约定。您还需要假设构造函数参数的类型和字段类型匹配。;)

我也会尽可能使用原语而不是包装器。使用int,除非您希望null是一个有效的选项。如果是这种情况,你应该考虑如何表示它。对于文本,我通常根据上下文为nullNaN使用空字符串或空白字段。

问题是,在Java中无法获取构造函数的参数名。

对于这个特殊的例子,您需要一个默认构造函数,使用它可以创建一个空对象。

public GivenClass() {
  super();
}

那么您可以使用反射来获取类的字段,然后为它们设置适当的值。

但是我认为注释你的构造函数,然后在你的deserialize方法中获取注释信息会容易得多。在这种情况下,您不需要获取字段并创建空构造函数。

例子:

您需要创建如下注释:

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property
{
    String value();
}

然后你可以像这样在你的构造函数中使用它:

public GivenClass(@Property("name") String name, @Property("location") String location, @Property("age") Integer age) {
  // ...
}

正如Peter Lawrey所说,强制类型转换不会将字符串转换为整数。

如果您的bean遵循标准bean约定(即您有getter &设置),然后可以使用BeanUtils。BeanUtils做了一些标准的转换,您可以通过添加converter来添加更多。

请看下面的例子:

import org.apache.commons.beanutils.BeanUtils;
public class BeanUtilsTest {
    public static class Obj {
        private int number;
        private String string;
        public void setNumber(int number) {
            this.number = number;
        }
        public void setString(String string) {
            this.string = string;
        }
        public String toString() {
            return "number=" + number + " string=" + string;
        }
    }
    public static void main(String args[]) throws Exception {
        String[] values = new String[] { "1", "two" };
        String[] properties = new String[] { "number", "string" };
        Obj obj = new Obj();
        for (int i = 0; i < properties.length; i++) {
            BeanUtils.setProperty(obj, properties[i], values[i]);
        }
        System.out.println("obj=" + obj);
    }
}

产生如下输出:

obj=number=1 string=two

注意,上面的例子只有setter,但仍然有效。

相关内容

  • 没有找到相关文章

最新更新