Обобщения и безопасность типов: проверка динамического связывания аргументов

Я застрял, пытаясь выяснить, как я могу использовать универсальные средства, чтобы проверить, является ли данный объект из суперкласса желаемым объектом из одного из подклассов подкласса этого суперкласса. Позвольте мне привести пример:

Допустим, у нас есть эта иерархия:

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;
    }
 }

Теперь я хочу сказать, что программа должна иметь возможность создавать объект из Conjunction только тогда и только тогда, когда заданные аргументы в конструкторе являются либо BooleanExpression, либо подклассом этого класса.

Я пытался использовать дженерики, как это:

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)
}

Но, к сожалению, это не компилируется! Я хочу использовать дженерики, чтобы проверить, left а также right являются примером BooleanExpressionпотому что Conjunction может быть только между двумя логическими значениями (а не PositionExpression). Тем не мение, left а также right может быть другим BooleanExpression, left может быть Conjunction в то время как right может быть BooleanTrue (как пример).

Итак, резюме: я хочу иметь возможность создать экземпляр Conjunction когда оба приведены аргументы left а также right являются подклассом BooleanExpression. Создание экземпляра Conjuction с одним из аргументов, являющихся подклассом PositionExpression не должен быть принят компилятором.

Я хочу решить это без изменения createConjunction метод и с использованием общих классов / интерфейсов. Есть идеи?

2 ответа

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)
    }

или вы можете изменить generic выражение в conjuction класс для

 Conjunction<T extends Expression> extends BooleanExpression{}

Если вы хотите сохранить сигнатуру метода 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);
}
Другие вопросы по тегам