2015-07-21 3 views
4

Я всегда слышал (и думал) Java как строго типизированный язык. Но только недавно я заметил что-то, что я использовал почти ежедневно: int и double перегрузка.Java-примитивы и перегрузка

Я могу написать следующее, и это действительно код Java:

int i = 1; 
double j = 1.5; 
double k = i + j; 

Но, если у меня есть метод, один из которых аргументов является double, мне нужно указать его:

public static <K, V> V getOrDefault(K k, Map<K, V> fromMap, V defaultvalue) { 
    V v = fromMap.get(k); 
    return (v == null) ? defaultvalue : v; 
} 

Когда слово вышеупомянутого метода на Map<String, Double>, то defaultvalue аргумент не может быть int:

getOrDefault(aString, aStringDoubleMap, 0); // won't compile 
getOrDefault(aString, aStringDoubleMap, 0d); // compiles and runs just fine 

Почему Java перегружает int до double (так же, как и в дополнение), а затем автобокс это до Double? Я думаю, что ответ заключается в том, как Java выполняет перегрузку оператора (т. Е. Перегрузка происходит в операторе +, а не от int до double), но я не уверен.

Здесь мы надеемся, что SO поможет мне в этом.

ответ

4

Это потому, что примитивы не работают с дженериками. Они должны быть в коробке.

Для вызова

getOrDefault(aString, aStringDoubleMap, 0); // won't compile 

работать, Java придется боксировать в 0 к Integer, а затем каким-то образом преобразовать его в Double. Этот язык не допускается. Это похоже на то, почему вы не можете сделать

Double value = 3; // Type mismatch: cannot convert from int to Double 

От JLS, on invocation contexts

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

Тип выражения, 0, целое число буквального, является int. Сыпучие Призыва контексты определяются как

Сыпучих Призыва контекстов позволяют более либеральный набор преобразований, , поскольку они используются только для конкретного вызова, если нет применимо заявления не может быть найдено с помощью строгих контекстов вызова. Сыпучие Призыва контекстов позволяют использовать один из следующих действий:

  • конверсия идентичности (§5.1.1)
  • расширяющего примитивного преобразования (§5.1.2)
  • ссылка уширения преобразования (§5.1.5)
  • преобразования бокса (§5.1.7), необязательно с последующим расширением преобразования ссылки
  • распаковки преобразования (§5.1.8), необязательно с последующим расширением примитивные преобразования

int к Double не поддерживается какой-либо из них.

Если вы просто имели

public static void main(String[] args) throws Exception { 
    method(3); 
} 

public static void method(double d) { 
} 

он будет работать.

+0

Вижу. Я думал, что Java будет * сначала конвертировать 0 в 0d (расширение конверсии, упомянутое Renjith и Andrew), и * then * autobox. Разумеется, преобразование из 'Integer' в' Double' не допускается, как вы указали. –

-1

int ->double преобразование - это расширяющееся преобразование. Расширение конверсий не теряет данных, поэтому они performed automatically.

+1

Это не вопрос ОП. Возникает вопрос, почему в 'Double d = 1;' буквальный '1' не преобразуется в' double', а затем автобоксируется в 'Double'. И нет, я не ответил на ваш ответ. – Turing85

+0

Возможно опечатка в вопросе? Цитата: «Почему Java перегружает int, чтобы удвоить (как и в дополнение), а затем автоматически перевести его в Double?» Я предполагаю, что он имел в виду «нет», но я пропустил это. – dsh

3

Вы ищете exciting section 5.2 of the Java Language specification.

Обычно, когда вы добавляете int и double, он выполняет расширяющееся преобразование. Но он не знает этого, пытаясь использовать Autobox для int в Double. На самом деле это явно запрещено.

+1

Это охватывает контексты вызова, а не контексты присваивания. –

+0

Это правда, это раздел 5.3 не 5.2, но список разрешений одинаковый в обоих разделах. –

1

Java не поддерживает перегрузку оператора (исключение является оператором String concat (+)).

double k = i + j; 

Вот что происходит неявно тип casting.A данных нижнего размера расширяется к типу данных более высокого размера. Это подразумевается JVM.

И для getOrDefault, примитивы обыкновенно работают с дженериками. И вот autoboxing. Когда вы вызываете getOrDefault(aString, aStringDoubleMap, 0d);, 0d будет автобоксирован для объекта Double. Но JVM не может автоблокировать 0 на объект Double в вашем первом случае.

Java не будет выполнять расширяющееся примитивное преобразование (от 0 до 0d) и преобразование бокса (двойное к двойному) неявно.

Проверить это link

неявное приведение от Int к удвоению, а затем бокс Double, не допускаются.

0 может быть только автобокс для целого. 0d может быть автообновлено до Double.

Смежные вопросы