Подтвердить что ты не робот

Могу ли я выполнять арифметические операции над базовым классом Number?

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

public class Example <T extends Number> {

    public T add(T a, T b){
        return a + b;
    }

}

Простите мою наивность, поскольку я относительно новичок в Java Generics. Этот код не скомпилируется с ошибкой:

Оператор + является undefined для типа аргумента (s) T, T

Я думал, что с добавлением "extends Number" код будет компилироваться. Возможно ли это сделать для Java или мне придется создавать переопределенные методы для каждого типа номера?

4b9b3361

Ответ 1

Число не имеет связанного с ним оператора +, а также не может быть, поскольку нет перегрузки оператора.

Было бы неплохо, однако.

В принципе, вы запрашиваете java для autobox - дескриптор номера, который включает в себя Integer, Float и Double, который может быть автобоксирован и иметь примененный оператор плюс, однако может существовать любое количество других неизвестных потомков Number, не может быть автобоксированным, и это невозможно узнать до выполнения. (Проклятое стирание)

Ответ 2

Ваша проблема не связана с дженериками, а не с операторами, примитивами и объектами, а также с автобоксированием.

Подумайте об этом:

public static void main(String[] args) {
    Number a = new Integer(2);
    Number b = new Integer(3);
    Number c = a + b;
}

Вышеописанное не компилирует

public static void main(String[] args) {
    Integer  a = new Integer(2);
    Integer b = new Integer(3);
    Number c = a + b;
}

Вышеприведенное компилируется, но только из-за автобоксинга - своего рода хакерский синтаксический клей, введенный в Java 5, и работает только (во время компиляции) с некоторыми конкретными типами: например, int-Integer.

За кулисами компилятор Java переписывает последний оператор ( "Я должен распаковать a и b, чтобы применить оператор sum с примитивными типами данных и поместить результат, чтобы назначить его объекту c" ) таким образом:

    Number c = Integer.valueOf( a.intValue() + b.intValue() );

Java не может распаковать a Number, потому что во время компиляции он не знает конкретный тип и, следовательно, не может угадать его примитивную копию.

Ответ 3

Вы можете сделать что-то вроде этого

    class Example <T extends Number> {
        public Number add(T a, T b){
            return new Double(a.doubleValue() + b.doubleValue());
        }
    }

Ответ 4

Да, Натан прав. Если вы хотите что-то вроде этого, вы должны написать это самостоятельно

public class Example <T extends Number> {
    private final Calculator<T> calc;
    public Example(Calculator<T> calc) {
       this.calc = calc;
    } 

    public T add(T a, T b){
        return calc.add(a,b);
    }
}

public interface Calculator<T extends Number> {
    public T add(T a, T b);
}

public class IntCalc implements Calculator<Integer> {
    public final static IntCalc INSTANCE = new IntCalc();
    private IntCalc(){}
    public Integer add(Integer a, Integer b) { return a + b; }
}

...

Example<Integer> ex = new Example<Integer>(IntCalc.INSTANCE);
System.out.println(ex.add(12,13));

Слишком плохо Java не имеет классов классов (Haskell) или неявных объектов (Scala), эта задача будет идеальным вариантом использования...

Ответ 5

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

Вы можете проверить, являются ли a и b экземпляром Long/Double/Integer/etc. и делегировать добавление к таким методам, как:

public Integer add(Integer a, Integer b) {
    return a+b; // this actually uses auto boxing and unboxing to int
}

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

Ответ 6

Рассмотрим Example<Number>, как бы + работать над этим? Существует не add или подобное в Number или даже таких, как Integer.

Хуже рассмотреть final class FunkyNumber extends Number { ... weird stuff, no add op ... }.

Ответ 7

Даже в библиотеке времени исполнения Java есть эта проблема, большинство методов, связанных с примитивами, должны дублировать ту же функциональность.

Самый быстрый вариант - записать код для одного типа, а затем скопировать его и заменить тип, чтобы сгенерировать методы для других типов. Для этого достаточно короткого script.