当我们写一个实体类的时候,我们有时需要重写toString
方法以方便我们查看类中字段的值,如果在重写toString()
时,纯手写各个字段的话(如下方代码),字段少了还好,字段多的话就....emmm!
static class Model extends Object {
String name;
int age;
String birthday;
public String getName() {
return name;
}
public Model setName(String name) {
this.name = name;
return this;
}
public int getAge() {
return age;
}
public Model setAge(int age) {
this.age = age;
return this;
}
public String getBirthday() {
return birthday;
}
public Model setBirthday(String birthday) {
this.birthday = birthday;
return this;
}
@NonNull
@Override
public String toString() {
return "[name=" + name
+ ",age=" + age
+ ",birthday=" + birthday+"]";
}
}
所以有必要寻求一种快速的方法,其实很简单:
static class Model extends Object {
String name;
int age;
String birthday;
public String getName() {
return name;
}
public Model setName(String name) {
this.name = name;
return this;
}
public int getAge() {
return age;
}
public Model setAge(int age) {
this.age = age;
return this;
}
public String getBirthday() {
return birthday;
}
public Model setBirthday(String birthday) {
this.birthday = birthday;
return this;
}
@NonNull
@Override
public String toString() {
StringBuilder result = new StringBuilder("[");
for (Field declaredField : Model.class.getDeclaredFields()) {
try {
result
.append(declaredField.getName())
.append("=")
.append(declaredField.get(Model.this))
.append(",");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return result.substring(0, result.length() - 1) + "]";
// return "[name=" + name
// + ",age=" + age
// + ",birthday=" + birthday + "]";
}
}
其实就是简单用到了Class中的几个方法。
那我们不能每新建一个实体类重写toString()时都写这些代码吧,虽然不多,但是我懒啊,那怎么办呢?很好办,把逻辑抽出来,新建一个静态方法,用的时候直接调用就好了。
static class Model extends Object {
String name;
int age;
String birthday;
public String getName() {
return name;
}
public Model setName(String name) {
this.name = name;
return this;
}
public int getAge() {
return age;
}
public Model setAge(int age) {
this.age = age;
return this;
}
public String getBirthday() {
return birthday;
}
public Model setBirthday(String birthday) {
this.birthday = birthday;
return this;
}
@NonNull
@Override
public String toString() {
return modelToString(this);
// StringBuilder result = new StringBuilder("[");
//
// for (Field declaredField : getClass().getDeclaredFields()) {
// try {
// result
// .append(declaredField.getName())
// .append("=")
// .append(declaredField.get(Model.this))
// .append(",");
// } catch (IllegalAccessException e) {
// e.printStackTrace();
// }
// }
//
// return result.substring(0, result.length() - 1) + "]";
// return "[name=" + name
// + ",age=" + age
// + ",birthday=" + birthday + "]";
}
}
public static <T> String modelToString(T t) {
StringBuilder result = new StringBuilder("[");
for (Field declaredField : t.getClass().getDeclaredFields()) {
try {
result
.append(declaredField.getName())
.append("=")
.append(declaredField.get(t))
.append(",");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return result.substring(0, result.length() - 1) + "]";
}
这样就简单多了,说了那么多我们简单测试一下。
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
System.out.println(new Model()
.setBirthday("2018-02-02")
.setName("娃娃")
.setAge(2)
.toString());
long sum = System.currentTimeMillis() - start;
System.out.println(String.valueOf(sum / 1000) + " 秒\n" + sum + " 毫秒");
}
输出如下:
[name=娃娃,age=2,birthday=2018-02-02]
0 秒
3 毫秒
Process finished with exit code
那种样是不是就完工了呢?其实不是,如果你访问的是没有访问权限的字段它会报错,就是这段
try {
result
.append(declaredField.getName())
.append("=")
.append(declaredField.get(t))
.append(",");
} catch (IllegalAccessException e) {
e.printStackTrace();
}
,假如你访问的是另一个类的private字段,会有
java.lang.IllegalAccessException:
的异常,我们来解决这个问题:
public static <T> String modelToString(T t) {
StringBuilder result = new StringBuilder("[");
for (Field declaredField : t.getClass().getDeclaredFields()) {
try {
result
.append(declaredField.getName())
.append("=")
.append(declaredField.get(t))
.append(",");
} catch (IllegalAccessException e) {
declaredField.setAccessible(true);
try {
result
.append(declaredField.get(t))
.append(",");
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
declaredField.setAccessible(false);
}
}
return result.substring(0, result.length() - 1) + "]";
}
如果我访问的是私有字段,我们先调用setAccessible(true)
使其有被访问权限,最后调用
declaredField.setAccessible(false);
关闭访问权限。
相信很多玩过Java反射的同学,都会想到这种方法!
其实不重写toString()
也是可行的,调用modelToString(T t)
时直接传对象,但不推荐这样做,麻烦,不省心!