【问题标题】:Generics and type safety: checking dynamic binding of arguments泛型和类型安全:检查参数的动态绑定
【发布时间】:2016-05-15 16:15:17
【问题描述】:

我一直在试图弄清楚如何使用泛型来检查来自超类的给定对象是否是来自该超类的子类的子类之一的所需对象。举个例子吧:

假设我们有一个这样的层次结构:

public interface Expression{
    public Object evaluate();
}

public abstract class BooleanExpression implements Expression{
    public abstract Boolean evaluate();
}

public abstract class PositionExpression implements Expression{
    public abstract Integer[] evaluate();
}

public class Conjunction extends BooleanExpression{
    public Boolean evaluate()
}

public class BooleanTrue extends BooleanExpression{
    @Override
    public Boolean evaluate(){
         return true;
    }
 }

现在我的观点是,当且仅当构造函数中的给定参数是 BooleanExpression 或此类的子类时,程序才应该能够从 Conjunction 构造对象。

我尝试过使用这样的泛型:

public class Conjunction<T extends BooleanExpression> extends BooleanExpression{
   public Conjuction(T left, T right){
        this.left = left;
        this.right = right;
   }

   private T left, right;

   @Override
   public Boolean evaluate(){
       return (left.evaluate() && right.evaluate())
   }

当我想创建一个实例时,我有以下代码:

public Expression createConjunction(Expression left, Expression right){
     return new Conjunction<BooleanExpression>(left, right)
}

但不幸的是,这不能编译!我想使用泛型来检查leftright 是否是BooleanExpression 的实例,因为Conjunction 只能介于两个布尔值之间(而不是PositionExpression)。 但是,leftright 可以不同,BooleanExpressionleft 可以是 Conjunction,而right 可以是 BooleanTrue(例如)。

回顾一下:当给定参数leftright 都是BooleanExpression 的子类时,我希望能够创建Conjunction 的实例。 编译器不应接受创建 Conjuction 的实例,其中一个参数是 PositionExpression 的子类。

我想在不更改 createConjunction 方法并使用泛型类/接口的情况下解决这个问题。有什么想法吗?

【问题讨论】:

  • 您肯定必须更改createConjunction 函数,因为在当前形式下它根本是无效的。您只需要更改leftright 的类型即可BooleanExpression 而不是Expression
  • 编译器正在做它应该做的事情。它无法编译,因为 leftrightExpressions,但您的 Conjuction 构造函数明确要求它们是 BooleanExpression 的子类。
  • @Casey 我猜编译器无法检查left 的底层对象是否属于BooleanExpression 的子类,是吗? (例如,当我调用此方法createConjunction 时,left 参数可能包含BooleanTrue,它是BooleanExpression 的子类(实现Expression 接口))
  • @luk2302 是的,我希望我不必这样做,因为在我当前的项目中,我不允许这样做。不过还是谢谢你的回答!
  • 您在这里面临的问题是编译器 不知道leftright 的实际内容。编译发生在运行时之前。如果对象实际上不包含合适的表达式,那么在运行时该方法会发生什么?返回空?抛出错误?开放的问题太多了。

标签: java generics parameter-passing type-safety dynamic-binding


【解决方案1】:
public Expression createConjunction(Expression left, Expression right){
     return new Conjunction<BooleanExpression>(left, right)
}

在上述方法中,您请求 2 个 expression 对象,但在 conjuction 构造函数它正在请求 2 个扩展 Booleanexpressions 的对象,这是您收到编译错误的部分。

您可以将 createConjuction 方法更改为

 public Expression createConjunction(BooleanExpression left, BooleanExpression right){
         return new Conjunction<BooleanExpression>(left, right)
    }

或者您可以将conjuction 类中的generic 表达式更改为

 Conjunction<T extends Expression> extends BooleanExpression{}

【讨论】:

    【解决方案2】:

    如果您确实想保留 createConjunction 方法的签名并且也不想更改 Conjunction 类,那么您可以检查并转换 createConjunction 方法中的参数类型。

    public Expression createConjunction(Expression left, Expression right){
        if( !(left instanceof BooleanExpression) || !(right instanceof BooleanExpression)){
            throw new IllegalArgumentException("wrong expression arguments, BooleanExpression expected");
        }
        BooleanExpression _left = (BooleanExpression)left;
        BooleanExpression _right = (BooleanExpression)right;
        return new Conjunction<BooleanExpression>(_left, _right);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-11
      • 2010-10-26
      • 1970-01-01
      • 1970-01-01
      • 2011-02-28
      • 2016-10-10
      • 2021-01-15
      • 2012-08-28
      相关资源
      最近更新 更多