Java: Getting the properties of a class to construct a string representation
Solution 1
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't use 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 StringBuilder
for constructing large dynamic strings.
I usually get my IDE (IntelliJ) to simply generate toString()
methods for me rather than using reflection for this.
Another interesting approach is to use the @ToString annotation from Project Lombok:
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.
Solution 2
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.
Solution 3
There is such an api, and it is called 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()
}
Solution 4
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();
}
Solution 5
Most IDEs provide a way to create a toString
method in a given class.
Given an Item
class with multiple fields:
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 Item
class above will create the following:
@Override
public String toString() {
return "Item [i=" + i + ", j=" + j + ", k=" + k + ", l=" + l + ", m="
+ m + ", n=" + n + ", o=" + o + "]";
}
Using reflection would 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 toString
method written at runtime is probably going to be more desirable.
Related videos on Youtube
Comments
-
Legend almost 2 years
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:
@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?
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?
-
Vadzim over 10 yearsSee also Auto-generating toString Method
-
-
Legend over 14 yearsActually the only reason I was thinking of Reflection is because I need to write a toString and a toJSON representation. I can write them manually but sometimes the classes represent items from a database so they could have a lot of fields. Would you still suggest a manual approach?
-
coobird over 14 yearsIt's really going to be up to the performance requirements of the toString and toJSON methods. If performance is not a concern, then using reflection probably isn't going to matter. If performance is a concern, it's probably going to be a good idea to profile the "manually" written code and code written using reflection, and see if the difference is going to matter.
-
Legend over 14 yearsUnderstood. Thanks for the explanation. I think I will need a performance. I am writing a REST web service so I guess the answer is pretty clear from your explanation.
-
coobird over 14 yearsAs always, when it comes to performance, it would be prudent to profile some code to be sure -- don't just take other people's words ;)
-
Legend over 14 years:) Thank You for that. I will go with the eclipse generation method for the toString representation and a reflection for toJSON and will profile it.
-
Legend over 14 yearsThank you for this. I would go with the first approach depending on the profiling results because the second approach uses one more library. I might have to write the toJSON for just three to four objects so I'll leave it to the profiling to decide.
-
Legend over 14 yearsThanks. This looks very interesting. Especially the method that uses no reflection.
-
Roel Spilker about 14 yearsFor Lombok, you only need a library during compilation. As long as you don't need @SneakyThrows, thare are no runtime-dependencies in Lombok