Java Generics не будет компилироваться - PullRequest
0 голосов
/ 03 июня 2019
public class GenMethodDemo{

        public GenMethodDemo(){
            Sum.<Integer,Integer,Integer>sum(1,2);       
        }

        public static void main(String args[]){
            new GenMethodDemo();
        }
    }

    class Sum{

     public static final <S extends Number,Z extends S,X extends S> S sum(Z v1,X v2){
            System.out.printf("v1=%1$s,v2=%2$s%n",v1.getClass(),v2.getClass());
            return v1+v2;
        }

Ошибка получения:

error: bad operand types for binary operator '+'
        return v1+v2;
  first type:  Z
  second type: X
  where Z,S,X are type-variables:
    Z extends S declared in method <S,Z,X>sum(Z,X)
    S extends Number declared in method <S,Z,X>sum(Z,X)
    X extends S declared in method <S,Z,X>sum(Z,X)
1 error

Не можете понять, что я делаю неправильно?Если я заменил SZX на Integer - все работает нормально, но почему с универсальным кодом код не компилируется?

Рефакторизованный код:

public class GenMethodDemo2{

    public GenMethodDemo2(){
        Sum.<Integer>sum(1,2);        
    }

    public static void main(String args[]){
        new GenMethodDemo2();
    }
}
class Sum{

    public static final <S extends Integer> S sum(S v1,S v2){
        System.out.printf("v1=%1$s, v2=%2$s%n",v1.getClass(),v2.getClass());
        return v1+v2;
    }
} 

error: incompatible types: int cannot be converted to S
        return v1+v2;
  where S is a type-variable:
    S extends Integer declared in method <S>sum(S,S)
1 error

Итак, S должен быть целым числом или любым подклассомкласса Integer, в любом случае это определенно должно быть возможно + их значения.Что не так с этой версией?

S extends Integer но int cannot be converted to S, как это может быть?Почему нет автобокса?

Ответы [ 2 ]

10 голосов
/ 03 июня 2019

Проблема, с которой вы сталкиваетесь, заключается в том, что для Number не определен оператор +, только конкретные подклассы Number.Например, + определено для Integer, Double и т. Д., Но не BigInteger, BigDecimal или какой-либо другой нестандартной реализации Number.

Не существует хорошего способасделать общее дополнение.В конечном итоге вам необходимо предоставить BinaryOperator<S>, поэтому ваш код выглядит следующим образом:

sum(1, 2, Integer::sum);
sum(1.0, 2.0, Double::sum);

, что более многословно, чем просто:

1 + 2
1.0 + 2.0

Для компилятора требуется + определяется для типов времени компиляции типов v1 и v2.Не имеет значения, если они Integer (или что-то еще) во время выполнения: решение о том, разрешить ли +, принимается компилятором, потому что он должен быть в состоянии гарантировать, что метод безопасен для типадля любых аргументов.

Приведенный выше метод компилируется в это:

 public static final Number sum(Number v1, Number v2){
   System.out.printf("v1=%1$s,v2=%2$s%n",v1.getClass(),v2.getClass());
   return v1+v2;
 }

Это называется стирание типа .

Если + isnНе определено для Number, этот код не разрешен.

0 голосов
/ 03 июня 2019

Как общее решение для всех встроенных Number расширений:

public static Number sum(final Number a, final Number b) {
    return new BigDecimal(a.toString()).add(new BigDecimal(b.toString()));
}

(Примечание: нет никакой гарантии, что toString() даст String, который может быть разобран BigDecimal, но этодля всех встроенных расширений JDK Number, насколько мне известно.)

Если вы хотите сделать что-то более умное, вы можете выполнить некоторые проверки с помощью instanceof, чтобы найти типы входов и работуоттуда, но я попробовал это один раз для реализации Comparable между всеми Number с, и производительность была не лучше, чем приведение к BigDecimal.

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