Java:获取类的属性以构造字符串表示

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1780896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 22:34:49  来源:igfitidea点击:

Java: Getting the properties of a class to construct a string representation

javareflectionclasstostringclass-variables

提问by Legend

Let's say I have a class like this (and also further assume that all the private variables:

假设我有一个这样的类(并进一步假设所有私有变量:

public class Item {
    private String _id = null;
    private String _name = null;
    private String _description = null;

        ...
}

Now, if I want to build a toString() representation of this class, I would do something like this inside the Item class:

现在,如果我想构建这个类的 toString() 表示,我会在 Item 类中做这样的事情:

@Override
public String toString() {
    return (_id + " " + _name + " " + _description);
}

But what if I have say 15 private variables inside the class? Do I have to write the name of each and every variable like this?

但是如果我在类中说 15 个私有变量呢?我是否必须像这样写出每个变量的名称?

Ideally, I would like to get over with the task by iterating through the list of private variables of this class and construct the string representation:

理想情况下,我想通过遍历此类的私有变量列表并构造字符串表示来完成任务:

@Override
public String toString() {
    ArrayList<String> members = getClass().getMembers(); //Some method like this
    String string = "";
    for(...)
        string += members[i] + " ";
}

Or perhaps a toJSON method, I would still need access to the names of these variables. Any suggestions?

或者可能是 toJSON 方法,我仍然需要访问这些变量的名称。有什么建议?

采纳答案by cletus

You could do:

你可以这样做:

@Override
public String toString() {
  StringBuilder sb = new StringBuilder();
  sb.append(getClass().getName());
  sb.append(": ");
  for (Field f : getClass().getDeclaredFields()) {
    sb.append(f.getName());
    sb.append("=");
    sb.append(f.get(this));
    sb.append(", ");
  }
  return sb.toString();
}

Don'tuse string concatenation to construct an end result from 15 data members, particularly if the toString()will be called a lot. The memory fragmentation and overhead could be really high. Use StringBuilderfor constructing large dynamic strings.

不要使用字符串连接来构造 15 个数据成员的最终结果,尤其是在toString()将被大量调用的情况下。内存碎片和开销可能非常高。使用StringBuilder构建大动态的字符串。

I usually get my IDE (IntelliJ) to simply generate toString()methods for me rather than using reflection for this.

我通常让我的 IDE (IntelliJ)toString()为我简单地生成方法,而不是为此使用反射。

Another interesting approach is to use the @ToString annotation from Project Lombok:

另一个有趣的方法是使用Project Lombok 中@ToString 注释

import lombok.ToString;

@ToString(excludes="id")
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  @ToString(callSuper=true, includeFieldNames=true)
  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}
import lombok.ToString;

@ToString(excludes="id")
public class ToStringExample {
  private static final int STATIC_VAR = 10;
  private String name;
  private Shape shape = new Square(5, 10);
  private String[] tags;
  private int id;

  @ToString(callSuper=true, includeFieldNames=true)
  public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
      this.width = width;
      this.height = height;
    }
  }
}

I find this much more preferable to, say, Jakarta Commons toString builders because this approach is far more configurable and it's also built at compile-time not run-time.

我发现这比 Jakarta Commons toString 构建器更可取,因为这种方法更具可配置性,而且它也是在编译时而非运行时构建的。

回答by Bhushan Bhangale

Check this API org.apache.commons.lang.builder.ToStringBuilder, it provides multiple ways to create toString usinf reflection or without reflection. Take a look at other subclasses as well.

检查这个 API org.apache.commons.lang.builder.ToStringBuilder,它提供了多种方式来创建 toString 使用反射或不反射。也看看其他子类。

回答by coobird

Most IDEs provide a way to create a toStringmethod in a given class.

大多数 IDE 提供了toString一种在给定类中创建方法的方法。

Given an Itemclass with multiple fields:

给定一个Item具有多个字段的类:

class Item {
    int i;
    int j;
    int k;
    int l;
    int m;
    int n;
    int o;  
}

For example, in Eclipse, performing "Generate toString()" feature on the Itemclass above will create the following:

例如,在 Eclipse 中,对Item上面的类执行“Generate toString()”功能将创建以下内容:

@Override
public String toString() {
    return "Item [i=" + i + ", j=" + j + ", k=" + k + ", l=" + l + ", m="
            + m + ", n=" + n + ", o=" + o + "]";
}

Using reflectionwould allow a programmatic way to observe one's own fields, but reflection itself is a fairly expensive (read: slow) process, so unless it is truly required, using a fixed toStringmethod written at runtime is probably going to be more desirable.

使用反射将允许以编程方式观察自己的字段,但反射本身是一个相当昂贵(读取:缓慢)的过程,因此除非确实需要,否则使用toString在运行时编写的固定方法可能会更可取。

回答by Milhous

You may run into the problem of speed. If you are using reflection, it can be really slow, in comparison to running native code. If you are going to use reflection, then you should probably have an in memory cache of the variables you are goaing to iterate over.

您可能会遇到速度问题。如果您使用反射,与运行本机代码相比,它可能真的很慢。如果您打算使用反射,那么您可能应该在内存中缓存要迭代的变量。

回答by Steven Levine

There is such an api, and it is called Java Reflection

有这么一个api,叫Java Reflection

To accomplish what you are requesting, you can simply do something like:

要完成您的要求,您可以简单地执行以下操作:

 Class<?> cls = this.getClass();
 Field fieldlist[] = cls.getDeclaredFields();
 for (Field aFieldlist : fieldlist) {
   // build toString output with StringBuilder()
 }

回答by medopal

This should be exactly what you are looking for

这应该正是您正在寻找的

    public String toString() {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(this.getClass().getName());
        Method m[] = c.getDeclaredMethods();
        Object oo;

        for (int i = 0; i < m.length; i++)
            if (m[i].getName().startsWith("get")) {
                oo = m[i].invoke(this, null);
                sb.append(m[i].getName().substring(3) + ":"
                        + String.valueOf(oo) + "\n");
            }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}

回答by bluish

Starting from the good medopal answer, you can use this code to have a string representation of all fields of an object, even if you are outside its class(obviously it's only for fields with a getter method):

好的 medopal answer 开始,您可以使用此代码来获得对象所有字段的字符串表示,即使您在其类之外(显然它仅适用于具有 getter 方法的字段):

/**Gives a string representation of the fields of the object
 * @param obj the object
 * @return
 */
private static String objectToString(Object obj) {
    StringBuilder sb = new StringBuilder();
    try {
        Class c = Class.forName(obj.getClass().getName());
        Method m[] = c.getDeclaredMethods();

        Object oo;
        for (int i = 0; i < m.length; i++)
            if (m[i].getName().startsWith("get")) {
                oo = m[i].invoke(obj, null);
                sb.append(m[i].getName().substring(3) + "="
                        + String.valueOf(oo) + "\n");
            }
    } catch (Throwable e) {
        System.err.println(e);
    }
    return sb.toString();
}