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

Groovy中字符串插值时重写HashMap.toString()失效的原因与解决

问题原因

Groovy的字符串插值("${xxx}")和as String类型转换,底层逻辑并不是直接调用对象的toString()方法。对于实现了Map接口的对象,Groovy内部有专门的字符串序列化逻辑,会直接调用AbstractMap(HashMap的父类)的原生toString()实现,完全绕过子类重写的方法。而直接调用.toString()时,遵循Java方法重写规则,所以会执行你自定义的逻辑。

解决办法

这里提供几个可行方案:

方案1:用组合替代继承(推荐)

不要直接继承HashMap,而是内部持有一个HashMap实例并实现Map接口。这样Groovy不会把它识别为原生Map,字符串插值和类型转换时会正常调用你重写的toString():

class Foo implements Map {
    private Map delegate = new HashMap()

    String toString() {
        "foo"
    }

    // 实现Map接口的所有方法,直接委托给内部的delegate
    @Override
    int size() { delegate.size() }

    @Override
    boolean isEmpty() { delegate.isEmpty() }

    @Override
    boolean containsKey(Object key) { delegate.containsKey(key) }

    @Override
    boolean containsValue(Object value) { delegate.containsValue(value) }

    @Override
    Object get(Object key) { delegate.get(key) }

    @Override
    Object put(Object key, Object value) { delegate.put(key, value) }

    @Override
    Object remove(Object key) { delegate.remove(key) }

    @Override
    void putAll(Map m) { delegate.putAll(m) }

    @Override
    void clear() { delegate.clear() }

    @Override
    Set keySet() { delegate.keySet() }

    @Override
    Collection values() { delegate.values() }

    @Override
    Set<Map.Entry> entrySet() { delegate.entrySet() }
}

方案2:重写asType方法

通过重写asType方法,指定转换为String类型时返回自定义内容,同时覆盖插值场景的逻辑:

class Foo extends HashMap {
    String toString() {
        "foo"
    }

    @Override
    Object asType(Class clazz) {
        if (clazz == String) {
            return toString()
        }
        super.asType(clazz)
    }
}

方案3:显式调用toString(临时 workaround)

如果不想修改类结构,在字符串插值时显式调用.toString(),强制触发自定义逻辑:

def test = new Foo()
test.put("abc", 123)
println "${test.toString()}" // 输出"foo"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 07:31:19