Java原语和重载



我一直听说(并且认为)Java是一种强类型语言。但是直到最近我才注意到一些我几乎每天都在使用的东西:intdouble过载。

我可以写以下代码,它是有效的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重载一个intdouble(就像它所做的),然后自动装箱到Double ?我认为答案在于Java如何操作符重载(即重载发生在+操作符中,而不是从intdouble),但我不确定。

希望SO能帮我解决这个问题。

这是因为原语不能与泛型一起使用。他们需要被装箱。

对于调用

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

要工作,Java必须将0装箱为Integer,然后以某种方式将其转换为Double。这是语言不允许的。这类似于为什么你不能

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

来自JLS,关于调用上下文

如果表达式的类型不能转换为对象的类型参数,通过松散调用上下文中允许的转换,然后出现编译时错误。

表达式0的类型为整型字面值int。松散调用上下文定义为

松散调用上下文允许更宽松的转换集合,因为它们只用于特定的调用,如果没有可以使用严格的调用上下文找到适用的声明。松散调用上下文允许使用以下方式之一:

  • 标识转换(§5.1.1)
  • 一个扩展的原语转换(§5.1.2)
  • 扩大参考转换(§5.1.5)
  • 一个装箱转换(§5.1.7)可选地跟随扩展引用转换
  • 一个拆箱转换(§5.1.8)可选地跟随一个扩展原语转换

int to Double不支持

如果你有

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

您正在寻找Java语言规范中令人兴奋的5.2节。

基本上当你添加int型和double型时,它执行扩展转换。但是当试图将int型自动装箱为Double型时,它不知道该怎么做。这是不允许的

Java不支持操作符重载(String concat(+)是个例外)。

double k = i + j;

这里发生的是隐式强制转换。较小大小的数据类型被扩展为较大大小的数据类型。这是由JVM隐式完成的。

对于getOrDefault,原语不能与泛型一起使用。这是autoboxing。当调用getOrDefault(aString, aStringDoubleMap, 0d);时,0d将自动装箱为Double对象。但是JVM不能在第一种情况下自动将0转换为Double对象。

Java不会隐式地执行扩展原语转换(0到0d)和装箱转换(double到double)。

查看此链接

不允许隐式地从int强制转换为double,然后装箱为double。

0只能自动装箱为整数。0d可以自动装箱为Double

int -> double是一个加宽转换。扩展转换不会丢失数据,因此会自动执行。

最新更新