【问题标题】:How to create list of Maps from List of Object in java without having getKey method?java - 如何在没有getKey方法的情况下从java中的对象列表创建地图列表?
【发布时间】:2019-06-18 11:33:41
【问题描述】:

如何创建一个映射列表,其中每个键名是从类属性的名称中推断出来的,值是通过getter方法放置的

我在 java 中有以下课程

class DTA {
  private String id;
  private String age;

  @Override
  public String toString() {
    return "DTA{" +
            "id='" + id + '\'' +
            ", age='" + age + '\'' +
            '}';
  }

  public DTA(String id, String age) {
    this.id = id;
    this.age = age;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getAge() {
    return age;
  }

  public void setAge(String age) {
    this.age = age;
  }
}

我有一个 DTA 类型的对象列表

List<DTA> listA = new ArrayList<>();
listA.add(new DTA("A", "15"));
listA.add(new DTA("B", "25"));

我想创建一个有序的地图列表(有点像 scala),其中包含以下内容。

List<? extends Map<String, String>>

List(Map("id"->"A", "age"->"15"), Map("id"->"B", "age"->"25"))

【问题讨论】:

    标签: java generics java-8 java-stream


    【解决方案1】:

    没有“动态”,直接的事情可能看起来像:

    List<Map<String, String>> x = listA
                .stream()
                .map(this::toMap)
                .collect(Collectors.toList());
    

    使用本地助手,例如:

    private Map<String, String> toMap(DTA dta) {
        Map<String, String> rv = new HashMap<>();
        rv.put("id", dta.getId());
        rv.put("age", dta.getAge());
        return rv;
    }
    

    为了在此处完全动态,您必须使用reflection 来查询字段名称。你可以找到示例如何做到这一点here

    但我强烈建议不要这样做:反思应该永远是你最后的手段。 DTA 的概念表明您无论如何都拥有来自某些“服务”的对象数据。如果是这样,为什么要先序列化为特定的 DTA 类,然后再将这些信息“扁平化”为一些通用的 Map 结构?!

    含义:当该服务为您提供序列化为 JSON 或 XML 的对象时......那么最好简单地使用像 gson 或 jackson 这样的库来直接反序列化数据到这种通用的“平面”基于地图的对象中。例如,杰克逊有一个 JsonNode 类。当您反序列化为此类对象时,您将免费获得字段名称的映射!更多示例代码见here

    重点是:使用反射识别字段是可能的。但是反射代码总是很乏味,而且容易出错。如果可能的话,不要自己这样做。

    【讨论】:

      【解决方案2】:

      基本上,用于“查看”Java 中类内容的工具称为反射。例如,如果您的对象是 POJO(Plain Old Java Object),您可以通过以下方式遍历类中的所有字段:

      DTA obj; // some object, I assume it's initialized
      Field[] fields = DTA.class.getDeclaredFields();
      Map<String, Object> valuesMap = new HashMap<>();
      for (field : fields) {
          boolean wasAccessible = field.isAccessible(); // check if class has access control disabled
          field.setAccessible(true); // disable access control (private/protected) to extract value    
          valuesMap.put(field.getName(), field.get(obj));
          field.setAccessible(wasAccessible); // return flag to initial value   
      }
      

      但是,以这种方式通过反射访问值是出了名的 hacky。除非您有充分的理由自己动手,否则请尝试使用能够自动执行此类任务的框架,而不是从头开始编写此类代码。

      另外,反射是。像这样为每个对象访问Field 实体是次优的,如果您真的想编写这样的代码,您应该将Field 对象缓存在Map&lt;String, Field&gt; 中,并且只执行setAccessible 覆盖和@987654326 @为每个DTA对象集合检索一次。

      【讨论】:

      • 不应该使用反射的原因的一个很好的列表,但还有一个例子如何做到这一点。好答案,值得一票!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      相关资源
      最近更新 更多