繁体   English   中英

通过反射在Java中投射对象

[英]Casting objects via reflection in 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和setters),则可以使用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

请注意,以上示例仅具有二传手,但仍然有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM