Тип возврата универсальный - PullRequest
0 голосов
/ 12 декабря 2018

Я учусь использовать дженерики в Java, и мне нужна следующая функция (в классе с универсальным атрибутом для работы:

public T evaluate() {
    if (arg.getValue() instanceof Boolean) {
        return !arg.getValue();
    } else if (arg.getValue() instanceof Integer) {
        return -arg.getValue();
    }
}

У класса есть атрибут arg типа Expression. Arg.getValueвозвращает переменную типа T. Функцияvaluate должна возвращать логическое отрицание arg.getValue, если T - логическое значение, и -arg.getValue, если T - целое число. Не компилируется, поскольку операторы - и! не могут быть примененыto T ".

Другой вариант заключается в реализации следующей идеи:

public T evaluate() {
    if (arg.getValue() instanceof Boolean) {
        Boolean b = (Boolean) arg.getValue();
        Boolean r = new Boolean(!b);
        return r;
    } else if (arg.getValue() instanceof Integer) {
        Integer i = (Integer) arg.getValue();
        Integer r = -i;
        return r;
    }
}

Но в этом случае возврат не работает:" несовместимые типы Обязательные: T Найдено: java.lang.Boolean / Integer "

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 12 декабря 2018

Это не так, как это работает.Универсальный тип не означает «я не знаю, что я верну, мы увидим в зависимости от того, что я получу, что может быть что-то из списка, зависящего от реализации».Тип T может быть переменным, но только во время реализации - во время выполнения он является фиксированным и может либо Boolean, либо Integer.

Так что вы можете сделать это

public interface Inverter<T> {
    // variable return type, depending on argument
    T invert(T toInvert);
}

с реализациями

class IntegerInverter implements Inverter<Integer> {
    // return type is fixed to integer
    Integer invert(Integer toInvert) {
        return -toInvert.intValue();
    }
}

class BooleanInverter implements Inverter<Boolean> {
    // return type is fixed to boolean
    Boolean invert(Boolean toInvert) {
        return !toInvert.booleanValue();
    }
}

Обратите внимание, что, вероятно, лучше повторно использовать существующие интерфейсы, например,

UnaryOperator<Integer> intInverter = i -> -i.intValue();
UnaryOperator<Boolean> boolInverter = b -> !b.booleanValue();

РЕДАКТИРОВАТЬ: предложение @Twometer приведет к чему-то вроде

class Inverters {
    public static UnaryOperator<Integer> integerInverter() {
        return i -> -i.intValue();
    }
    public static UnaryOperator<Boolean> boolInverter() {
        return b -> !b.booleanValue();
    }

    // and maybe even this, but this will still require a cast
    // at the client
    public static <T> UnaryOperator<?> inverter(Class<T> clazz) {
        if (clazz == Integer.class) {
            return integerInverter();
        } else if (clazz == Boolean.class) {
            return boolInverter();
        }
        throw new IllegalArgumentException(String.format("Cannot create inverter for class %s", clazz));
    }
}

Таким образом, у вас есть центральный способ получения необходимых вам инверторов;Таким образом, вы уверены, что они будут использованы повторно.Кроме того, вы можете кэшировать созданные лямбды, не изменяя код клиента.

0 голосов
/ 12 декабря 2018

Обобщения помогут, только если два класса, между которыми вы хотите провести различие, имеют (полезный) общий суперкласс.Однако первый общий суперкласс Boolean и Integer - это Object, что бесполезно.

Если ваша цель - изучить дженерики, я предлагаю использовать например Integerи Double, которые оба имеют общий подкласс Number, так что вы можете определить T как T extends Number

Если ваша цель в точности как ваш пример, тогда [править] вы можете следовать за @ daniuответить.

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