foo(int, int) is picked over foo(int...)

Viewed 107

In this piece of code, why the compiler is not able to reference the method that has varargs argument from static context.

 private static void doSomething(int... nums) {
    System.out.println("1");
}
private void doSomething(int num1, int num2) {
    System.out.println("2");
} 

public static void main(String[] args) {
    doSomething(1,2);
}

JDK 17 is complaining Cannot make a static reference to the non-static method doSomething(int, int) . Is this a bug or another feature I am not aware of.

JDK 8 and JDK 11 dont complain about it!

4 Answers

The behavior of rejecting the method invocation is correct. Method resolution should find the most specific method first and check for the static modifier afterwards.

But there is a bug in javac from version 7 to 16.

See

JDK-8268474, Method resolution should stop on static error

Javac is not in sync with section §15.12.3 of the JLS 16 specification. In particular, for invocations in static context, javac too early checks whether the method is static, and when it determines it is not static and cannot be called, proceeds to a further phase in method lookup, even though it should report a compile-time error.

This bug has been fixed with JDK 17.

Note that Eclipse’s compiler ECJ does not have this bug, so the example is rejected in Eclipse, regardless of which JDK version you use.

Only invocations using a simple name are affected. When you use ClassName.doSomething(1,2);, all versions will resolve the invocation to doSomething(int num1, int num2) and generate the correct error.

The doSomething method which takes two ints is an instance method and you are trying to call it without creating an instance of the object first.

Why should the compiler accept that? I highly doubt, that in any prior JDK it behaved differently.

A static method can call only other static methods; it cannot call a non-static method. So that's why the non-static doSomething function is always called.

In order to call the doSomething(int, int) you have to make it static or create an object of the class containing the method and then call the method using the object.

YourClass obj = new YourClass();
obj.doSomething(1, 2);

varargs are replacement for arrays. Compiler is giving you error because you are calling doSomething in a manner which is not acceptable for varargs:

To call your varargs method you should call something like:

doSomething(new int [] {1,2});

By this way, you will be correctly calling private static void doSomething(int... nums)

Tested this in JDK8 (8u41) & on JDK17.

Moreover, calling dosomething(1,2) is giving error on both JDK8 & JDK17 so I am not finding anything different on both versions.

Related