简体   繁体   中英

Java subclass does not recognise its generic superclass

I need help with a problem I have with generics in Java. I'm writing this Computer algebra system, where the user enters a math expression and the system works with it in different ways (expand it, simplify it etc). It worked fine for expressions containing natural numbers, and I wanted to expand it to work with mathematical sets as well. Instead of +, you would have the intersection operator, etc.

At first, I started recording everything for the sets, but then I realized this was probably not good and started using generics.

Instead of having one parse tree like MathExpr and one like SetExpr , I thought I could just have a generic Expression<T> and build a base class Number and a base class Set .

To try to clarify, I want a mathematical expression like (2 * a) + (3 + 2) to be an instance of a class Expression<Number> and a set expression like (A ∪ B) ∩ C to be an instance of Expression<Set> . I can then perform different operations on this, like calculate the depth etc.

The + operation is implemented as one class, the * as one class etc. Both these classes are subclasses of an abstract class called TwoExpr which in turn is a subclass of the abstract class Expr . This is how I have done it now and everything works fine.

When I wanted to change my code I made my Expr class generic. That is Expr<T> . I also changed TwoExpr to TwoExpr<T> and created a base class Number .

The problem is, now I can't seem to instantiate objects of the type Sum<Number> .

I get a " Type mismatch: cannot convert from Sum to Expr<Number> " error. But Sum is a subclass of TwoExpr<Number> , which in turn is a subclass of Expr<Number> . As you may realize, I can't make the class Sum generic and call it Sum<Number> , because all arithmetic operations don't have analogues for sets.

I have always been able to create objects like

Expr zero= new Leaf(0);
Variable a = new Variable("a");
Expr aPlusZero = new Sum(a, zero);

When I changed to generics, the same code looks like this:

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

How come it doesn't recognize that Sum(a,zero) is a subclass of Expr<Number> , when it says in the declaration of Sum

public class Sum extends TwoExpr<Number> {

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

and in the declaration of 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;
    }
    ...
}

I know that Lizkows substitution principle doesn't apply for generic arguments. But Number isn't a subclass of anything (except Object) and don't have any subclasses. I hope I've been fairly clear about what I'm trying to do and what problem I have. Does anybody have any idea how to solve it? Please tell me if anything was unclear in the above or if you want more code.

Thanks in advance.

Mattias

I think your problem is in the classes you did not show, I tried the following and it works:

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

Might it be that Variable is not an Expr?

UPDATE:

I played a little creating Variable and Leaf as I imagine them and it all works:

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

If you take the extends Expr from Variable it does give the error you experience, might it be this the cause?

Maybe try to debug it:

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

Furthermore maybe is a better solution for your system.

Sum does not import Types.Number . So it's not Expr<Types.Number> but Expr<java.lang.Number> . I would assume this would give a compilation error not only on the assignment but also on the construction of new Sum(vA, zero) , but maybe the compiler sees the other error first.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM