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

Java泛型如何返回不同类型?流畅DSL构建器类型问题

问题描述

我正在为某DSL开发Java流畅接口,采用构建器模式实现各部分DSL的构建。问题在于,特定构建器有时需要将控制权转移到另一个构建器,之后再返回至“父构建器”。例如,SequenceBuilder用于创建语句列表,有时需要切换到IfBuilder构建if语句,完成后需返回SequenceBuilder。部分构建器的调用者类型不固定,因此需要能够返回不同类型的构建器。示例代码如下:

package com.example.fluent;

public class Test {

    public class Type1 {
        public Type1 test1() {
            System.out.println("test1");
            return this;
        }
        public Type3 gotype3() {
            System.out.println("gotype3");
            return new Type3<Type1>(this);
        }
        public void endtype1() {
            System.out.println("endtype1");
        }
    }

    public class Type2 {
        public Type2 test2() {
            System.out.println("test2");
            return this;
        }
        public Type3 gotype3() {
            System.out.println("gotype3");
            return new Type3<Type2>(this);
        }
        public void endtype2() {
            System.out.println("endtype2");
        }
    }

    public class Type3<T> {
        private T parent;
        public Type3(T parent) {
            this.parent = parent;
        }
        public Type3 test3() {
            System.out.println("test3");
            return this;
        }
        public T endtype3() {
            System.out.println("endtype3");
            return parent;
        }
    }

    public static void main(String[] args) {
        new Test().run();
    }

    private void run() {
        new Type1()
            .test1()
            .gotype3()
                .test3()
                .endtype3()
            .test1() // 此处编译报错,因为endtype3()返回Object而非Type1
            .endtype1();
    }
}

在run()方法中,创建Type1实例并遵循构建器模式,调用gotype3()方法切换到Type3构建器,通过构造函数传入Type1引用以便后续返回。但调用endtype3()时,泛型本应返回Type1类型,却被转换为Object类型,导致无法调用Type1的方法,破坏了流畅接口模式。

问题:是否存在其他方法,能让子构建器返回正确类型的父构建器?

解决方案

核心修复:明确泛型返回类型

你的问题根源是Type3的test3()方法返回了原始类型Type3,而非带泛型参数的Type3<T>,导致链式调用中泛型信息被擦除。只需修改Type3的test3()方法,明确返回泛型化的类型即可:

public class Type3<T> {
    private T parent;
    public Type3(T parent) {
        this.parent = parent;
    }
    // 修改返回类型为Type3<T>,保留泛型信息
    public Type3<T> test3() {
        System.out.println("test3");
        return this;
    }
    public T endtype3() {
        System.out.println("endtype3");
        return parent;
    }
}

同时,建议把Type1和Type2中的gotype3()方法返回类型也改为泛型化的Type3<Type1>和Type3<Type2>,进一步避免类型模糊:

// Type1中的方法修改
public Type3<Type1> gotype3() {
    System.out.println("gotype3");
    return new Type3<>(this);
}

// Type2中的方法修改
public Type3<Type2> gotype3() {
    System.out.println("gotype3");
    return new Type3<>(this);
}

修改后,endtype3()会正确返回T的具体类型(如Type1),链式调用就能正常继续。

进阶方案:递归泛型约束父构建器

如果需要构建更复杂的层级结构,可让父构建器使用递归泛型来约束自身类型,确保所有方法都能返回正确的子类类型,避免重复的类型转换:

// 基础构建器抽象类,用递归泛型约束自身
public abstract class BaseBuilder<T extends BaseBuilder<T>> {
    @SuppressWarnings("unchecked")
    protected T self() {
        return (T) this;
    }
}

// Type1继承BaseBuilder,指定自身为泛型参数
public class Type1 extends BaseBuilder<Type1> {
    public Type1 test1() {
        System.out.println("test1");
        return self();
    }
    public Type3<Type1> gotype3() {
        System.out.println("gotype3");
        return new Type3<>(this);
    }
    public void endtype1() {
        System.out.println("endtype1");
    }
}

// Type2同理
public class Type2 extends BaseBuilder<Type2> {
    public Type2 test2() {
        System.out.println("test2");
        return self();
    }
    public Type3<Type2> gotype3() {
        System.out.println("gotype3");
        return new Type3<>(this);
    }
    public void endtype2() {
        System.out.println("endtype2");
    }
}

这种方式适合需要频繁扩展的构建器体系,能让代码更简洁且类型安全。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:10:20