通过Java反射实现POJO实例转字符串的通用方法

  • Post author:
  • Post category:java


最近在根黑马教程的书自学java,虽然说java有些老了,我也不年轻了,但认真学一学还是能发现不少乐趣。

教程中有一个常用代码是重写POJO类的toString()方法以使打印输出实例时可以看到实例的值,而不是内存地址。对每个POJO类都重写一遍结构相同的代码简直是浪费生命,而单纯的复制粘贴然后再修改也不是好的解决方法。因为以前使用C#时对反射比较熟悉,就想着写一个工具方法来实现这个功能,到时只需要在toString()方法中调用这个方法就好了。网上搜了一下相关文章,然后就开始吧。

工具方法代码(思路见代码注释),使用用静态方法方便调用:

package com.itheima.utils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.ArrayList;

public class Object2String {
	public static <T> String convertToString(T object) {
		if(object == null) {
			return null;
		}
		// 获取当前对象的类型和类型名称
		Class<?> clazz = object.getClass(); 
		String className = clazz.getSimpleName();
		// 如果类型名称中包含_$$_则认为是匿名代理类
		// 这是考虑到mybatis在使用嵌套查询方式时返回的ResultMap使用代理包装
		// TODO:是否有更好的判断方式,有待查证
		if (className.contains("_$$_")) {
			// 使用代理类时,获取代理类的父类,因为mybatis代理类用的时cglib代理,
			// 通过动态生成子类来扩展目标类的行为
			clazz = clazz.getSuperclass();
			className = clazz.getSimpleName();
		}
		
		// 获取类中的所有字段,包括私有字段,使用getFields不能获取私有字段
		Field[] fields = clazz.getDeclaredFields();
		List<String> fvs = new ArrayList<String>(); //用于存放字段名称和值,格式为filed=value
		Field.setAccessible(fields, true); //设置私有字段可访问,否则将无法读取私有字段的值
		for (Field field : fields) {
			String name = field.getName();
			String value = "null";
			try {
				value = String.valueOf(field.get(object));
			} catch (Exception e) {
				e.printStackTrace();
			}
			fvs.add(name + "=" + value);
		}
		// 使用String.join()方法将字段名称和值拼接为字符串并用指定分隔符分隔
		String info = className + "[" + String.join(", ", fvs) + "]";
		return info;
	}
}

创建一个POJO类用来做测试,在重写的toString方法中调用工具方法:

package com.itheima.po;

import com.itheima.utils.Object2String;

public class Customer {
	private Integer id;
	private String username;
	private String jobs;
	private String phone;
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getJobs() {
		return jobs;
	}
	public void setJobs(String jobs) {
		this.jobs = jobs;
	}
	public String getPhone() {
		return phone;
	}
	public void setPhone(String phone) {
		this.phone = phone;
	}
	
	@Override
	public String toString() {
		return Object2String.convertToString(this);
	}
	
}

写一个测试类用来检验效果,这里没有测试动态代理的效果,也就是工具类中clazz.getSuperclass()部分的代码,以后有时间再补上:

package com.itheima.test;

import org.junit.Test;
import com.itheima.po.Customer;

public class UtilsTest {
	// 辅助方法用于方便打印输出,虽然也可以使用静态导入out字段实现,
	// 但总觉得使用import static没有简单写个方法方便
	private void println(Object object) {
		System.out.println(object);
	}
	
	@Test
	public void convert2StringTest() {
		Customer customer = new Customer();
		customer.setId(1);
		customer.setUsername("小六");
		customer.setJobs("哎就是玩");
		customer.setPhone("16894666888");
		println(customer);
	}
}

展示一下效果,还不错吧:

在这里插入图片描述

如果大家有更好的方法或思路,还请不吝赐教呀。



版权声明:本文为xCyansun原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。