Подкласс Java не распознает свой универсальный суперкласс - PullRequest
3 голосов
/ 22 марта 2011

Мне нужна помощь в решении проблемы с дженериками в 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) и не имеет подклассов. Надеюсь, я достаточно ясно понял, что я пытаюсь сделать и какие у меня проблемы. У кого-нибудь есть идеи, как это решить? Пожалуйста, скажите мне, если что-то было неясно в вышеупомянутом или если вы хотите больше кода.

Заранее спасибо.

Маттиас

Ответы [ 3 ]

2 голосов
/ 22 марта 2011

Я думаю, что ваша проблема в классах, которые вы не показали, я попробовал следующее, и это работает:

Expr<Number> zero= new Expr<Number>();
Expr<Number> a= new Expr<Number>(); 
Expr<Number> APlusZero=new Sum(a,zero);

Может быть, переменная не является Expr?

UPDATE:

Я немного поиграл в создание Variable и Leaf, как я их себе представляю, и все это работает:

public class Number {

    public Number(int i){}
}


public class Variable<T> extends Expr<T> {

    public Variable(String s){}
}


public class Leaf<T> extends Expr<T> {

    public Leaf(T t) {
        super();
    }
}


public class Expr<T> {

}


public class TwoExpr<T> extends Expr<T> {

    public TwoExpr(Expr<T> a, Expr<T> b) {
    }
}


public class Sum extends TwoExpr<Number> {

    public Sum(Expr<Number> a, Expr<Number> b) {
        super(a, b);
    }
}


public class AllTogether {

    public static void main(String[] args) {

        Expr<Number> zero= new Leaf<Number>(new Number(0));
        Variable<Number> a = new Variable<Number>("a");
        Expr<Number> APlusZero=new Sum(a,zero);
    }
}

Если вы возьмете Extd extends из Variable, он выдаст ошибку, с которой вы столкнулись, может ли это быть причиной?

0 голосов
/ 22 марта 2011

Sum не импортирует Types.Number.Так что это не Expr<Types.Number>, а Expr<java.lang.Number>.Я бы предположил, что это даст ошибку компиляции не только при присваивании, но и при построении new Sum(vA, zero), но, возможно, компилятор сначала увидит другую ошибку.

0 голосов
/ 22 марта 2011

Возможно, попробуйте отладить его:

Object = new Sum(a,zero);
System.out.println(o.getClass().getGenericSuperclass());

Более того, возможно, это лучшее решение для вашей системы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...