You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于自定义toString格式实现对象实例化的技术咨询

实现自定义toString逆向的toObject方法

背景说明

现有自定义toString方法用于生成特定格式的对象序列化字符串:

@NotNull
public static String toString(@NotNull Object object, @NotNull Object[] variables, Class<?>... parameters) throws NoSuchMethodException {
    StringBuilder sb = new StringBuilder();
    sb.append(object.getClass().getConstructor(parameters)).append('\n');
    sb.append(object.getClass()).append(":");
    for (Object variable : variables){
        sb.append(" | ").append(variable.toString());
    }
    return sb.toString();
}

该方法生成的字符串示例如下:

public User(java.lang.String,int)
class User: | username | 369172

需要实现逆向方法toObject,将上述格式的字符串转换为原对象的新实例,需解决三个核心问题:

  • 未知参数/变量数量时,将变量转换为可用于实例化的形式
  • 适配对象构造方法为私有的场景
  • 处理参数为输出默认Object.toString()结果的对象
    要求:禁止使用Serialization接口

完整实现代码

import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ObjectConverter {

    // 原自定义toString方法
    @NotNull
    public static String toString(@NotNull Object object, @NotNull Object[] variables, Class<?>... parameters) throws NoSuchMethodException {
        StringBuilder sb = new StringBuilder();
        sb.append(object.getClass().getConstructor(parameters)).append('\n');
        sb.append(object.getClass()).append(":");
        for (Object variable : variables){
            sb.append(" | ").append(variable.toString());
        }
        return sb.toString();
    }

    // 实现的逆向toObject方法
    @NotNull
    public static Object toObject(@NotNull String formattedObject, @NotNull Object object, Class<?>... parameters) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
        // 拆分格式化字符串为构造方法行和变量行
        String[] lines = formattedObject.split("\n");
        if (lines.length != 2) {
            throw new IllegalArgumentException("非法的格式化字符串格式");
        }
        String constructorLine = lines[0];
        String variablesLine = lines[1];

        // 解析构造方法参数类型(如果未传入parameters则从字符串提取)
        Constructor<?> constructor;
        if (parameters == null || parameters.length == 0) {
            Pattern constructorPattern = Pattern.compile("\\((.*?)\\)");
            Matcher matcher = constructorPattern.matcher(constructorLine);
            if (!matcher.find()) {
                throw new IllegalArgumentException("无法解析构造方法行");
            }
            String paramTypesStr = matcher.group(1);
            String[] paramTypeNames = paramTypesStr.isEmpty() ? new String[0] : paramTypesStr.split(",");
            List<Class<?>> paramTypeList = new ArrayList<>();
            for (String typeName : paramTypeNames) {
                typeName = typeName.trim();
                try {
                    paramTypeList.add(Class.forName(typeName));
                } catch (ClassNotFoundException e) {
                    // 处理基本类型映射
                    switch (typeName) {
                        case "int": paramTypeList.add(Integer.TYPE); break;
                        case "long": paramTypeList.add(Long.TYPE); break;
                        case "double": paramTypeList.add(Double.TYPE); break;
                        case "float": paramTypeList.add(Float.TYPE); break;
                        case "boolean": paramTypeList.add(Boolean.TYPE); break;
                        case "byte": paramTypeList.add(Byte.TYPE); break;
                        case "short": paramTypeList.add(Short.TYPE); break;
                        case "char": paramTypeList.add(Character.TYPE); break;
                        default: throw new IllegalArgumentException("无法识别的参数类型:" + typeName);
                    }
                }
            }
            parameters = paramTypeList.toArray(new Class[0]);
        }

        // 处理私有构造方法:获取声明的构造方法并开启访问权限
        constructor = object.getClass().getDeclaredConstructor(parameters);
        constructor.setAccessible(true);

        // 解析变量值并转换为对应类型
        String[] variableStrs = variablesLine.split(" \\| ");
        List<Object> variableValues = new ArrayList<>();
        for (int i = 1; i < variableStrs.length; i++) {
            String varStr = variableStrs[i].trim();
            Class<?> paramType = parameters[i-1];
            variableValues.add(convertStringToType(varStr, paramType, object.getClass()));
        }

        // 实例化并返回对象
        return constructor.newInstance(variableValues.toArray());
    }

    /**
     * 字符串转目标类型,处理默认Object.toString()场景
     */
    private static Object convertStringToType(String valueStr, Class<?> targetType, Class<?> targetClass) throws NoSuchFieldException, IllegalAccessException {
        // 处理基本类型及包装类
        if (targetType.isPrimitive()) {
            if (targetType == Integer.TYPE) return Integer.parseInt(valueStr);
            if (targetType == Long.TYPE) return Long.parseLong(valueStr);
            if (targetType == Double.TYPE) return Double.parseDouble(valueStr);
            if (targetType == Float.TYPE) return Float.parseFloat(valueStr);
            if (targetType == Boolean.TYPE) return Boolean.parseBoolean(valueStr);
            if (targetType == Byte.TYPE) return Byte.parseByte(valueStr);
            if (targetType == Short.TYPE) return Short.parseShort(valueStr);
            if (targetType == Character.TYPE) return valueStr.charAt(0);
        } else if (targetType == String.class) {
            return valueStr;
        } else if (Number.class.isAssignableFrom(targetType)) {
            if (targetType == Integer.class) return Integer.valueOf(valueStr);
            if (targetType == Long.class) return Long.valueOf(valueStr);
            if (targetType == Double.class) return Double.valueOf(valueStr);
            if (targetType == Float.class) return Float.valueOf(valueStr);
            if (targetType == Byte.class) return Byte.valueOf(valueStr);
            if (targetType == Short.class) return Short.valueOf(valueStr);
        } else if (Boolean.class == targetType) {
            return Boolean.valueOf(valueStr);
        } else {
            // 匹配默认Object.toString()格式:类名@十六进制哈希码
            Pattern defaultToStringPattern = Pattern.compile("(.*?)@[0-9a-fA-F]+");
            Matcher matcher = defaultToStringPattern.matcher(valueStr);
            if (matcher.matches()) {
                // 优先尝试无参构造实例化
                try {
                    Constructor<?> noArgsConstructor = targetType.getDeclaredConstructor();
                    noArgsConstructor.setAccessible(true);
                    return noArgsConstructor.newInstance();
                } catch (NoSuchMethodException e) {
                    // 无参构造不存在时,尝试获取静态单例字段(如INSTANCE)
                    try {
                        Field instanceField = targetType.getDeclaredField("INSTANCE");
                        instanceField.setAccessible(true);
                        return instanceField.get(null);
                    } catch (NoSuchFieldException | InvocationTargetException | InstantiationException ex) {
                        throw new IllegalArgumentException("无法解析默认toString格式的对象:" + valueStr);
                    }
                } catch (InvocationTargetException | InstantiationException ex) {
                    throw new RuntimeException("实例化默认toString对象失败", ex);
                }
            } else {
                throw new IllegalArgumentException("不支持的参数类型转换:" + targetType.getName());
            }
        }
        throw new IllegalArgumentException("无法转换字符串为指定类型:" + targetType.getName());
    }
}

核心问题解决细节

1. 未知参数/变量数量处理

  • 通过正则表达式从构造方法行中提取参数类型全限定名,转换为Class对象
  • 拆分变量行内容,按顺序匹配参数类型,调用转换方法将字符串转为对应实例
  • 使用动态列表存储参数类型和变量值,适配任意数量的输入参数

2. 私有构造方法适配

  • 使用getDeclaredConstructor获取类中所有声明的构造方法(包括私有)
  • 调用constructor.setAccessible(true)开启反射访问权限,允许调用私有构造方法实例化对象

3. 默认Object.toString()结果处理

  • 正则匹配类名@十六进制哈希码格式,识别默认toString输出
  • 优先尝试通过无参构造方法实例化(同样开启私有访问权限)
  • 无参构造不存在时,尝试获取常见静态单例字段(如INSTANCE)
  • 若以上方式均不支持,抛出明确的异常提示

内容的提问来源于stack exchange,提问作者Alexandrite2000

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:48:11