3

Consider the following code

public class Foo
{

  int value;
  public Foo (final String str, Object ... bug)
  {
    System.out.println ("Should work! 1");
  }

  public Foo (final String str, final int value, Object ... bug)
  {
     this.value = value;
    System.out.println ("Should work! 2");
  }

  public static void main (String[]args)
  {
    Foo f = new Foo ("Foo", 3); //Line 14
    System.out.println(f.value);
  }
}

When I was using jdk-1.6.x I was successfully able to compile it. but upon upgrading to jdk-1.7 it gives me error :

Foo.java:18: error: reference to Foo is ambiguous, both constructor Foo(String,Object...) in Foo and constructor Foo(String,int,Object...) in Foo match Foo f = new Foo ("Foo", 3); //Line 14

So to avoid this error I changed second Ctor to

  public Foo (final String str, final Integer value, Object ... bug)
  {
     this.value = value;
    System.out.println ("Should work! 2");
  }

So that it can autobox to Integer and skip the compilation error.

Few question :
1) Is it a good practise ? If not then is there other way ?
2) Why java developer would have taken the decision to give error instead of allowing it ?

peeyush
  • 2,841
  • 3
  • 24
  • 43

2 Answers2

4

This is by design and a known area of incompatibility between Java 6 and Java 7 because the overload-resolution algorithm was fixed in Java 7. In Java 5 and 6, the following code would not compile:

class Test {
    void foo(int... i) {}
    void foo(double... d) {}

    void test() {
       foo(1,2,3);
    }
}

The compiler would complain that the calls were ambiguous. But this isn't true because double is more general than int and therefore int is the most-specific option in this case.

However this fix resulted in an incompatibility (look at the release notes; search for "varargs"). The upshot is that you cannot choose the most-specific method when you have int and Object because neither is a subtype of the other. So this shouldn't compile. However, you can use Integer, because Integer is a subtype of Object and in this case it is the most-specific option and so the compiler can choose that.

Pertinent section from the release notes:

While the javac compiler accepts more code than it did prior to JDK 7, this fix also results in a slight source incompatibility in the following case:

class Test {
    void foo(int... i) {}
    void foo(Object... o) {}

    void test() {
       foo(1,2,3);
    }
}

This code compiles in JDK 6 (the most specific method is foo(int...)). This code does not compile under JDK 7. As per 15.12.2.5, it is not possible to choose between foo(int...) and foo(Object...) as neither int is a subtype of Object, nor Object is a subtype of int. This program should be disallowed (in fact, it should never have been allowed in the first place).

Nature of Incompatibility: behavioral and source

RFE: 6199075

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
1

Why java developer would have taken the decision to give error instead of allowing it ?

The error occurs due to a change in the way var-args are perceived in JDK 7.

1) Is it a good practise ? If not then is there other way ?

While you can use Integers to get around the problem, the class Foo originally had an int as its member variable and I'd keep it that way. Note that Integer value; can now accept null. Check for null in your code and use value.intValue() to assign the value to the member variable.

Uncaught NPEs and performance are big nuisances with autoboxing / unboxing.

Deepak Bala
  • 11,095
  • 2
  • 38
  • 49