Java 基元和重载
Java primitives and overloading
我一直听说(并认为)Java 是一种强类型语言。但直到最近我才注意到我几乎每天都在使用的东西:int
和 double
重载。
我可以写下面的,而且是有效的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 能帮我解决这个问题。
int
-> double
转换是扩大转换。扩大转换不会丢失数据,因此它们是 performed automatically.
那是因为基元不适用于泛型。他们需要装箱。
对于调用
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
If the type of the expression cannot be converted to the type of the
parameter by a conversion permitted in a loose invocation context,
then a compile-time error occurs.
表达式 0
的类型,整数文字,是 int
。松散调用上下文定义为
Loose invocation contexts allow a more permissive set of conversions,
because they are only used for a particular invocation if no
applicable declaration can be found using strict invocation contexts.
Loose invocation contexts allow the use of one of the following:
- an identity conversion (§5.1.1)
- a widening primitive conversion (§5.1.2)
- a widening reference conversion (§5.1.5)
- a boxing conversion (§5.1.7) optionally followed by widening reference conversion
- an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion
int
到 Double
不受任何这些支持。
如果你有
public static void main(String[] args) throws Exception {
method(3);
}
public static void method(double d) {
}
它会起作用。
您正在寻找 exciting section 5.2 of the Java Language specification。
基本上,当您添加一个 int 和 double 时,它会执行扩大转换。但是在尝试将 int 自动装箱为 Double 时,它不知道要执行此操作。事实上,这是明确不允许的。
Java不支持运算符重载(String concat(+)除外)运算符。
double k = i + j;
这里发生的事情是隐式的 casting.A 较小的数据类型被扩展为较大的数据类型。这是由 JVM 隐式完成的。
而对于 getOrDefault
,原语无法与 generics.And 一起使用 autoboxing
。
当您调用 getOrDefault(aString, aStringDoubleMap, 0d);
时,0d 将自动装箱为 Double 对象。
但是在第一种情况下,JVM 无法将 0 自动装箱到 Double 对象。
Java 不会隐式执行扩大原始转换(0 到 0d)和装箱转换(double 到 Double)。
勾选这个link
不允许从 int 到 double 的隐式转换,然后装箱到 Double。
0 只能自动装箱为整数。
0d 可以自动装箱为 Double。
我一直听说(并认为)Java 是一种强类型语言。但直到最近我才注意到我几乎每天都在使用的东西:int
和 double
重载。
我可以写下面的,而且是有效的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 能帮我解决这个问题。
int
-> double
转换是扩大转换。扩大转换不会丢失数据,因此它们是 performed automatically.
那是因为基元不适用于泛型。他们需要装箱。
对于调用
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
If the type of the expression cannot be converted to the type of the parameter by a conversion permitted in a loose invocation context, then a compile-time error occurs.
表达式 0
的类型,整数文字,是 int
。松散调用上下文定义为
Loose invocation contexts allow a more permissive set of conversions, because they are only used for a particular invocation if no applicable declaration can be found using strict invocation contexts. Loose invocation contexts allow the use of one of the following:
- an identity conversion (§5.1.1)
- a widening primitive conversion (§5.1.2)
- a widening reference conversion (§5.1.5)
- a boxing conversion (§5.1.7) optionally followed by widening reference conversion
- an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion
int
到 Double
不受任何这些支持。
如果你有
public static void main(String[] args) throws Exception {
method(3);
}
public static void method(double d) {
}
它会起作用。
您正在寻找 exciting section 5.2 of the Java Language specification。
基本上,当您添加一个 int 和 double 时,它会执行扩大转换。但是在尝试将 int 自动装箱为 Double 时,它不知道要执行此操作。事实上,这是明确不允许的。
Java不支持运算符重载(String concat(+)除外)运算符。
double k = i + j;
这里发生的事情是隐式的 casting.A 较小的数据类型被扩展为较大的数据类型。这是由 JVM 隐式完成的。
而对于 getOrDefault
,原语无法与 generics.And 一起使用 autoboxing
。
当您调用 getOrDefault(aString, aStringDoubleMap, 0d);
时,0d 将自动装箱为 Double 对象。
但是在第一种情况下,JVM 无法将 0 自动装箱到 Double 对象。
Java 不会隐式执行扩大原始转换(0 到 0d)和装箱转换(double 到 Double)。
勾选这个link
不允许从 int 到 double 的隐式转换,然后装箱到 Double。
0 只能自动装箱为整数。 0d 可以自动装箱为 Double。