Мне нужна помощь в решении проблемы с дженериками в Java. Я пишу эту систему компьютерной алгебры, где пользователь вводит математическое выражение, и система работает с ним по-разному (расширяйте его, упрощайте и т. Д.). Он хорошо работал для выражений, содержащих натуральные числа, и я хотел расширить его для работы с математическими наборами. Вместо + у вас будет оператор пересечения и т. Д.
Сначала я начал записывать все для наборов, но потом понял, что это, вероятно, нехорошо, и начал использовать дженерики.
Вместо того, чтобы иметь одно дерево синтаксического анализа, например MathExpr
, и такое, как SetExpr
, я подумал, что мог бы просто иметь универсальный Expression<T>
и создать базовый класс Number
и базовый класс Set
.
Чтобы попытаться уточнить, я хочу, чтобы математическое выражение типа (2 * a) + (3 + 2) было экземпляром класса Expression<Number>
, а выражение множества типа (A ∪ B) ∩ C было бы экземпляр Expression<Set>
. Затем я могу выполнять различные операции над этим, например, вычислять глубину и т. Д.
Операция + реализована как один класс, * как один класс и т. Д. Оба эти класса являются подклассами абстрактного класса с именем TwoExpr
, который, в свою очередь, является подклассом абстрактного класса Expr
. Вот как я это сделал сейчас, и все работает отлично.
Когда я захотел изменить свой код, я сделал класс Expr
родовым. Это Expr<T>
. Я также изменил TwoExpr на TwoExpr<T>
и создал базовый класс Number
.
Проблема в том, что теперь я не могу создать экземпляр объекта типа Sum<Number>
.
Я получаю ошибку "Type mismatch: cannot convert from Sum to Expr<Number>
". Но Sum
является подклассом TwoExpr<Number>
, который, в свою очередь, является подклассом Expr<Number>
. Как вы понимаете, я не могу сделать класс Sum
универсальным и назвать его Sum<Number>
, потому что все арифметические операции не имеют аналогов для множеств.
Мне всегда удавалось создавать такие объекты, как
Expr zero= new Leaf(0);
Variable a = new Variable("a");
Expr aPlusZero = new Sum(a, zero);
Когда я перешел на дженерики, тот же код выглядит так:
Expr<Number> zero= new Leaf<Number>(new Number(0)); //works fine
Variable<Number> a = new Variable<Number>("a"); //works fine
Expr<Number> APlusZero=new Sum(a,zero); //gives a "Type mismatch:
//cannot convert from Sum to Expr<Number>" error
Почему он не признает, что Sum(a,zero)
является подклассом Expr<Number>
, когда говорится в объявлении суммы
public class Sum extends TwoExpr<Number> {
public Sum(Expr<Number> a, Expr<Number> b) {
super(a, b);
}
...
}
и в декларации TwoExpr
public abstract class TwoExpr<T> extends Expr<T> {
protected Expr<T> a;
protected Expr<T> b;
public TwoExpr(Expr<T> a, Expr<T> b) {
this.a=a;
this.b=b;
}
...
}
Я знаю, что принцип замещения Лизкова не применим к общим аргументам. Но Number не является подклассом чего-либо (кроме Object) и не имеет подклассов.
Надеюсь, я достаточно ясно понял, что я пытаюсь сделать и какие у меня проблемы. У кого-нибудь есть идеи, как это решить? Пожалуйста, скажите мне, если что-то было неясно в вышеупомянутом или если вы хотите больше кода.
Заранее спасибо.
Маттиас