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

解决Java布尔表达式树中接口方法参数的歧义问题

问题

我需要在Java中运行由布尔表达式生成的布尔运算树,让它迭代执行并返回布尔值,示例表达式如下:

boolean b = AND(isNumberEven("4"), AND(isNumberOdd("7"), isNumberEven("6")));

公司要求支持多种节点类型:双分支的逻辑运算符节点(如And、Or),以及作为叶子节点的属性检查节点(如isSomething、hasInArray)。

我尝试设计两个接口分别对应逻辑运算符与属性检查,但编写的代码存在泛型类型问题,编译器无法推断fire()方法的正确类型。我习惯了JavaScript的动态类型,想知道如何在Java中正确实现这种树形布尔运算结构,解决接口方法参数的歧义问题?

附上我尝试的代码实现:

class PropertyCheckingInput {
   String s; // 模拟属性,这个对象是我们要验证属性的目标(比如判断这个字符串是否为偶数)

   PropertyCheckingInput(...){...} // 包含所有参数的构造方法
}

interface PropertyChecking {
   boolean fire(PropertyCheckingInput i);
}

class LogicOperatorInput<
   T extends LogicOperator or PropertyChecking, // 可以是两者之一
   Ti extends LogicOperatorInput or PropertyCheckingInput
> {
    T left;
    Ti leftInput;
    T right;
    Ti rightInput;

    // 可能leftInput的类型应该和left的类型匹配,但我不知道怎么用Java泛型强制约束

    LogicOperatorInput(...){...} // 包含所有参数的构造方法
}

interface LogicOperator{
   boolean fire(LogicOperatorInput i); 
}

And类实现示例:

class And implements LogicOperator {
    boolean fire(LogicOperatorInput i) {
        i.left.fire(i.leftInput) && i.right.fire(i.rightInput);
    }

    And() {}

    public static void main(String[] args) {
        // 表达式:isNumberEven("4") AND isNumberOdd("7") AND isNumberEven("6")
        boolean b = new And().fire(new LogicOperatorInput(
            new isNumberEven(), 
            new PropertyCheckingInput("4"), 
            new And(), 
            new LogicOperatorInput(
                new isNumberOdd(), 
                new PropertyCheckingInput("7"), 
                new isNumberEven(), 
                new PropertyCheckingInput("6"))
        ));

        System.out.println(b);
    }
}
解决方案

核心思路是统一所有节点的接口,让逻辑运算符和属性检查节点都实现同一个顶层接口,这样整个运算树的节点可以统一处理,避免泛型歧义。

1. 定义统一的布尔节点接口

创建一个顶层接口BooleanNode,所有节点(包括逻辑运算符和属性检查器)都实现它,这样不管是分支节点还是叶子节点,都可以用同一个方法执行:

@FunctionalInterface
interface BooleanNode {
    boolean evaluate();
}

使用@FunctionalInterface是因为每个节点只需要一个执行方法,也方便后续用Lambda简化实现。

2. 实现属性检查叶子节点

属性检查节点作为叶子节点,直接封装检查逻辑和输入参数,不需要依赖外部输入:

// 通用的属性检查输入类,可根据实际需求扩展字段
class PropertyInput {
    private final String value;

    public PropertyInput(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

// 检查数字是否为偶数的节点
class IsNumberEven implements BooleanNode {
    private final PropertyInput input;

    public IsNumberEven(PropertyInput input) {
        this.input = input;
    }

    @Override
    public boolean evaluate() {
        try {
            int num = Integer.parseInt(input.getValue());
            return num % 2 == 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}

// 检查数字是否为奇数的节点
class IsNumberOdd implements BooleanNode {
    private final PropertyInput input;

    public IsNumberOdd(PropertyInput input) {
        this.input = input;
    }

    @Override
    public boolean evaluate() {
        try {
            int num = Integer.parseInt(input.getValue());
            return num % 2 != 0;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}

3. 实现逻辑运算符分支节点

逻辑运算符节点(And、Or)作为分支节点,持有左右两个子节点(可以是任何BooleanNode类型,包括其他逻辑节点或属性检查节点):

// And逻辑运算符节点
class And implements BooleanNode {
    private final BooleanNode left;
    private final BooleanNode right;

    public And(BooleanNode left, BooleanNode right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean evaluate() {
        // 短路求值,和Java原生&&行为一致
        return left.evaluate() && right.evaluate();
    }
}

// Or逻辑运算符节点
class Or implements BooleanNode {
    private final BooleanNode left;
    private final BooleanNode right;

    public Or(BooleanNode left, BooleanNode right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public boolean evaluate() {
        // 短路求值,和Java原生||行为一致
        return left.evaluate() || right.evaluate();
    }
}

4. 测试运行

现在可以按照你想要的方式构建布尔运算树并执行,代码结构和示例表达式完全对应:

public class BooleanTreeDemo {
    public static void main(String[] args) {
        // 构建表达式:isNumberEven("4") AND (isNumberOdd("7") AND isNumberEven("6"))
        BooleanNode tree = new And(
                new IsNumberEven(new PropertyInput("4")),
                new And(
                        new IsNumberOdd(new PropertyInput("7")),
                        new IsNumberEven(new PropertyInput("6"))
                )
        );

        boolean result = tree.evaluate();
        System.out.println(result); // 输出 true
    }
}

方案优势

  • 统一接口消除泛型歧义:所有节点都实现BooleanNode,不需要区分逻辑节点和属性节点的输入类型,每个节点自己封装所需的输入和逻辑。
  • 符合Java静态类型要求:每个节点职责明确,编译器可以清晰推断类型,避免原代码中LogicOperatorInput的泛型混乱。
  • 扩展性强:新增逻辑运算符(如Not)或属性检查节点时,只需要实现BooleanNode接口即可,无需修改现有结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 16:24:59