Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java primitives and overloading

I have always heard (and thought of) Java as a strongly typed language. But only recently did I notice something that I have been using almost on a daily basis: int and double overloading.

I can write the following, and it is valid Java code:

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

But, if I have a method, one of whose arguments is a double, I need to specify it:

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

When I call the above method on a Map<String, Double>, the defaultvalue argument cannot be an int:

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

Why does Java overload an int to double (just like it does in addition), and then autobox it to Double? I think the answer lies in how Java does operator overloading (i.e. the overloading happens in the + operator, and not from int to double), but I am not sure.

Here's hoping that SO can help me out on this.

like image 538
Chthonic Project Avatar asked Mar 16 '23 08:03

Chthonic Project


1 Answers

That's because primitives don't work with generics. They need to be boxed.

For the invocation

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

to work, Java would have to box the 0 to an Integer, then somehow convert that to a Double. That's not allowed by the language. It's similar to why you can't do

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

From the 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.

The type of the expression, 0, an integer literal, is int. Loose invocation contexts are defined as

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 to Double is not supported by any of those.

If you simply had

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

public static void method(double d) {
}

it would work.

like image 65
Sotirios Delimanolis Avatar answered Mar 26 '23 14:03

Sotirios Delimanolis