Проблемы с Java Generics и арифметикой сложения

Кто-нибудь знает, почему я получаю эту ошибку?

ошибка: не удается найти символ return left.evaluate() + right.evaluate(); символ: метод Assessment() местоположение: переменная слева от типа T, где T — тип-переменная: T extends Object, объявленный в классе Operation

package expevaluator;

interface Expression<T> {

    T evaluate();
}

class Constant<T> implements Expression {

    private final T value;

    public Constant(T value) {
        this.value = value;
    }

    @Override
    public T evaluate() {
        return value;
    }

}

abstract class Operation<T> implements Expression {

    public T left;
    public T right;
}

class Addition<T> extends Operation {

    public Addition(T left, T right) {
        super.left = left;
        super.right = right;
    }

    @Override
    public T evaluate() {
        if(left instanceof Integer){
            if(right instanceof Integer){
                return super.left.evaluate() + right.evaluate();
            }else{
                return left.evaluate() + right.evaluate(); 
            }
        }else{
            return left.evaluate() + right.evaluate();
        }
    }
}

РЕДАКТИРОВАТЬ:

package expevaluator;

import java.util.logging.Level;
import java.util.logging.Logger;

interface Expression<T extends Number> {

    T evaluate();
}

class Constant<T extends Number> implements Expression{

    private final T value;

    public Constant(T value) {
        this.value = value;
    }

    @Override
    public T evaluate() {
        return this.value;
    }

}

abstract class Operation<T> implements Expression {
    public T left;
    public T right;
}

class Addition extends Operation {

    public Addition(Constant left, Constant right) {
        super.left =  left.evaluate();
        super.right = right.evaluate();
    }

    @Override
    public Number evaluate() {
        String name = "expevaluator." + super.left.getClass().getSimpleName() + super.right.getClass().getSimpleName() + "Addition";
        try {
            Object instance;
            instance = Class.forName(name).newInstance();
            return (Number) instance;
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            Logger.getLogger(Addition.class.getName()).log(Level.SEVERE, null, ex);
        }
        /*if (super.left instanceof Integer && super.right instanceof Integer) return new IntIntAddition().evaluate((Integer)super.left,(Integer)super.right);
        if (super.left instanceof Integer && super.right instanceof Double) return new IntDoubleAddition().evaluate((Integer)super.left,(Double)super.right);
        if (super.left instanceof Double && super.right instanceof Integer) return new DoubleIntAddition().evaluate((Double)super.left,(Integer)super.right);
        if (super.left instanceof Double && super.right instanceof Double) return new DoubleDoubleAddition().evaluate((Double)super.left,(Double)super.right);*/
        return null;

    }

}

class IntegerIntegerAddition{

    IntegerIntegerAddition() {

    }

    public Number evaluate(int left, int right) {
        return left + right;
    }

}

class IntegerDoubleAddition {

    public IntegerDoubleAddition() {
    }

    public Number evaluate(int left, double right) {
        return left + right;
    }
}
class DoubleIntegerAddition {

    public DoubleIntegerAddition() {
    }

    public Number evaluate(double left, int right) {
        return left + right;
    }
}
class DoubleDoubleAddition {

    public DoubleDoubleAddition() {
    }

    public Number evaluate(double left, double right) {
        return left + right;
    }
}

Мне это удалось, теперь я хочу использовать отражение в классе сложения.

Я хочу создать экземпляр класса, а затем вызвать метод оценки().


person Subiendo    schedule 31.03.2014    source источник


Ответы (3)


T никогда не ограничивается, поэтому его верхняя граница равна Object. Поэтому доступны только методы на Object.

Вы смешиваете тип значения выражения (T, который может быть Integer) и сами подвыражения (подтипы Expression). Возможно, это должно выглядеть так:

public Addition(Expression<T> left, Expression<T> right) {
   //...

Также обратите внимание, что Constant<T> и подобные должны реализовывать Expression<T>, а не необработанный тип Expression. Точно так же Addition<T> должен расширять Operation<T>, а не Operation.

Тем не менее, ваш подход к Addition в целом не работает, потому что он не может распространяться на общий случай (вы не можете просто применить оператор + к любому произвольному типу). Я бы реализовал Addition исключительно для случая Integer:

class IntegerAddition extends Operation<Integer> {

    private final Expression<Integer> left, right;

    public IntegerAddition(Expression<Integer> left, Expression<Integer> right) {
        this.left = left;
        this.right = right;
    }

    public Integer evaluate() {
        return left.evaluate() + right.evaluate();
    }
}
person Mark Peters    schedule 31.03.2014
comment
Знаете ли вы, как добавить отражение в мой метод оценки, потому что я хочу запустить метод оценки во время выполнения? - person Subiendo; 02.04.2014

У тебя как минимум две проблемы.

  • left и right относятся к типу T, но вы пытаетесь вызвать для них evaluate(), который определен в классе Constant<T>. Поскольку left и right не обязательно относятся к типу Constant<?>, компилятор не может понять эти вызовы.
  • Вы пытаетесь добавить два выражения типа T. Это не имеет смысла для большинства типов, которыми может быть T. Например, что вы ожидаете от a + b, если a и b оба имеют тип Color или InputStream или что-то еще, что не имеет смысла добавлять?
person Dawood ibn Kareem    schedule 31.03.2014

Вам нужно преобразовать super.left в Expression или любой другой тип, который содержит функцию evaluate() во время компиляции. Помните, что java имеет стирание типов и является строго типизированным языком, ваш метод Addition.Evaluate() не знает, какой тип left и right будет во время компиляции, а поскольку в операции не определена функцияvalu(), возникает ошибка компиляции.

public T evaluate() {
    if(left instanceof Integer){
        if(right instanceof Integer){
            return ((Expression)super.left).evaluate() + ((Expression)right).evaluate();
        }else{
            return ((Expression)left).evaluate() + ((Expression)right).evaluate(); 
        }
    }else{
        return ((Expression)left).evaluate() + ((Expression)right).evaluate();
    }
}

Кроме того, вы не можете добавлять объекты, возвращаемые методом evaluate(), поскольку дженерики в java на самом деле просто набираются как Java.Lang.Object. Вместо этого вам понадобится метод add() с поддержкой типов, который выполняет добавление за вас с помощью оператора instanceOf, поскольку в java невозможно переопределить оператор «+». (Это похоже на то, чего вы пытаетесь достичь, просто вы еще не прошли все 100 ярдов)

Просто подумайте о «переменных» универсального типа как о бессмысленных в java, они просто помогают вам избежать ошибок типа во время компиляции, но компилируются до их необработанных типов в байтовом коде.

Редактировать:

Кроме того... я не совсем уверен, что насчет блока:

if(left instanceof Integer){
        if(right instanceof Integer){

Затем вы продолжаете вызывать left.evaluate() и пытаетесь добавить его к right.evaluate()... но проблема здесь в том, что у вас, кажется, нет ничего, что было бы производным от Integer, поэтому все, что у вас осталось, это код, который ведет себя странно. Если вы ДЕЙСТВИТЕЛЬНО знаете, что будете иметь дело с целыми числами и что все ваши вложенные объекты left и right также будут Integer, вам следует просто привести выражения к типу int, а затем сложить их вместе. Более того, вы должны квалифицировать свои типы с помощью Integer, чтобы вы работали с классом Addition, квалифицированным не как универсальный тип.

person TTT    schedule 31.03.2014