Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor ambiguity with varargs in java 8

Tags:

java

In the class below, I get a compilation error with Java 8 due to an ambiguous call to this(). With Java 6 this class compiled fine, though. I know I could refactor this using factory methods and such but for the actual class where the problem occurs, I would strongly prefer to maintain the current API for now.

Can anyone think of a way to resolve the ambiguity without changing the external API?

public class Vararg8 {

    public Vararg8(final Object... os) {}

    public Vararg8(final boolean b,
                   final String s,
                   final int... is) {}

    public Vararg8() {
        this(true, "test", 4, 5, 6);
    }
}
like image 896
Ozymandias Avatar asked Aug 30 '16 12:08

Ozymandias


People also ask

How many values can be accommodated by Varargs in Java?

There can be only one variable argument in a method. Variable argument (Varargs) must be the last argument.

At which position should Varargs be placed in a parameterized method?

There can be only one variable argument in the method. Variable argument (varargs) must be the last argument.

What is Varargs in Java & How it works?

Varargs is a short name for variable arguments. In Java, an argument of a method can accept arbitrary number of values. This argument that can accept variable number of values is called varargs. The syntax for implementing varargs is as follows: accessModifier methodName(datatype… arg) { // method body }

How do the overloading methods can be ambiguous?

Sometimes unexpected errors can result when overloading a method that takes a variable length argument. These errors involve ambiguity because both the methods are valid candidates for invocation. The compiler cannot decide onto which method to bind the method call.


2 Answers

You can do it by passing an explicit int[] array:

public Vararg8()
{
  this(true, "test", new int[]{4, 5, 6});
}

You might notice that this is still, in one sense, ambiguous: what you've passed is still compatible with the Object... constructor. The reason this works is that method resolution goes in various stages, and only the last stage allows consideration of varargs parameters. Because you've used an explicit array, it hits the second one fine without needing varargs expansion. It can't hit the first one without varargs expansion, so that wouldn't be considered till the final stage.

See the appropriate JLS docs:

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

The second phase (§15.12.2.3) performs overload resolution while allowing boxing and unboxing, but still precludes the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the third phase.

The third phase (§15.12.2.4) allows overloading to be combined with variable arity methods, boxing, and unboxing.

like image 147
chiastic-security Avatar answered Oct 06 '22 20:10

chiastic-security


Try this:

public Vararg8()
{
  this(true, "test", new int[]{4, 5, 6});
}
like image 22
Robert Kock Avatar answered Oct 06 '22 18:10

Robert Kock